Wednesday, August 15, 2012

Creating A Digitally Signed Security Token For A REST API

Recently I was tasked with securing a Web API. I wanted to use token authentication that didn't require that I look up a user id from that token for every request. In order to do this, I knew I'd have to embed the user id and possibly some other data in the token string and make it tamper-proof (esque).

My solution was to use RSA digital signing to sign a my token string to ensure it hasn't been tampered with. Then I'd have to send the signature as part of the token string in order to have something to check on the other end. Digital signing with RSA uses the private key to sign some data, and then the public key (or private key, if in a safe environment) to verify the signature.

EDIT: I wanted to express the advantage of having a public key, because I didn't really say anything about that in my initial post: A big advantage to using an asymmetric algorithm to do the digital signing is the fact that you can share a public key. If you have third party applications consuming your API, you can assign each of them a key pair, storing their private key yourself and giving them the public key. They can then use the public key to verify your tokens independently without making a call to your API for any reason.

There are a few drawbacks to doing things this way rather than some sort of token where you're looking up the token in a database:


  • The biggest drawback is you're limited in the amount of information that can be attached to your token without making your token huge. How big is too big? Well, that's up to you, really. But I like to keep mine under 200-300 characters or so, depending on how I'm sending it back and forth.
  • The other drawback is you must expire these types of tokens, since there is no way to manually expire tokens like this from the server side. Otherwise once you issue the token, it's good forever until you change your private key.

What follows is a simplified version of my solution. What I did was a bit different, as I did some custom binary serialization to reduce the size of my token string, but overall this is the general idea:




2 comments:

  1. So I spent some time on this, and am using it with a few modifications. Let me start by saying what I was planning originally.

    I was going to just use some symmetric key encryption as the client doesn't need to know what's encoded in the token, so I wouldn't need to distribute the key. Besides being able to do cryptographic attacks on the cipher text being sent back and forth, they'd have to gain access to the key store on the server, which in that case symmetric vs asymmetric isn't the issue. There maybe other vulnerabilities I'm missing though.

    However, I'm using asymmetric key encryption like you did anyways. It makes my inner geek happy.

    Anyways, I added a sliding window value and I'm using key container to store/retrieve the key. I just use .NET's KeyContainer by setting the appropriate params when instantiating the RSACryptoServiceProvider.

    For the sliding window, I just added another int64 to the constructor and the token. If more than half the time has elapsed of the sliding window and the token has not expired, I generate a new token setting a new expiration time. Other sliding window tokens I've read about regenerate at 1/2 or more, but not less. I think it'll reduce the amount of cryptography is done, which is probably more overhead than date/time arithmetic.

    Don't worry. I'll note your blog post in the code and you'll get the credit/blame for it. :-)

    ReplyDelete
  2. Lol... blame. Always the blame.

    There are a lot of ways to skin this cat. Another way to do it, is to just hash the contents with a secret and use that as the signature. It's not quite as secure though.

    Another benefit if my model I didn't really even go over is that you can actually share a public key with consuming apps (if there are more than one you'd want to use more than one private key as well, but whatever)... then those apps will be able to indepedently verify the signature of the token.

    It retrospect, it probably would have been easier if I'd made the signature the first part of the token byta array... *shrug* it works.

    ReplyDelete

This form allows some basic HTML. It will only create links if you wrap the URL in an anchor tag (Sorry, it's the Blogger default)