31

I want to make sure requests can't be forged and sent on to my server. In order to do this I need to generate an API key per user on my system. The purpose of the key will be to sign requests on the client side & validate them on the server.

The question is, what are API keys generally made up of? Are they just a cryptographically secure random number (similar to a password salt)? Or is there some logic behind them e.g. should they be made up of data specific to the user.

In my system each user already has a unique ID (GUID) which isn't publically exposed, could I use this as my "key" or should an API key differ from a users ID?

James
  • 1,698
  • 3
  • 13
  • 18

1 Answers1

24

It depends on how much you want to separate roles.

Basic system: your "signature" is a MAC. The "API key" is a secret value with is shared between the server and the user. Normal MAC algorithms like HMAC can use arbitrary sequences of bits as key, so a key is easily generated by using /dev/urandom (Linux, *BSD, MacOS X), calling CryptGenRandom() (Win32) or using java.security.SecureRandom (Java).

Enhanced system: your signature is a true digital signature. This makes sense if you want to separate the key generator (who can produce keys which will be accepted by the server) from the server itself (who validates the incoming signatures). Keys for signature algorithms are mathematical objects with a lot of internal structure, and each algorithm implies a specific key generation algorithm. Use a library which already implements the needed bits (e.g. OpenSSL).


Either way, there is more to it than just key generation and signatures. For instance, you probably want to avoid replay attacks: an ill-intentioned third party spies on the network, and records a valid request signed by a regular user. Later on, the attacker sends the request again, complete with its signature, so as to replicate the effect. To avoid replay attacks, you must add some sort of external protocols, and these things are hard to do (it is not hard to define a protocol; it is very hard to define a secure protocol). Therefore, the smart thing to do is reusing an existing, well-vetted protocol, which, in practice, means SSL/TLS.

With SSL, the "basic system" is reduced to sending the API key in a header at the beginning of the conversation (that's exactly what happens with password authentication on HTTPS Web sites). The "enhanced system" is then "SSL with a client certificate".

Thomas Pornin
  • 320,799
  • 57
  • 780
  • 949
  • The API is running over SSL and I actually use the Basic authentication approach for the initial request. However, I need to store an authentication token on the client side to be used for subsequent requests. I am aware using SSL would mitigate MitM/Replay attacks as the channel is encrypted, however, this won't prevent someone from forging a request....right? – James Sep 05 '12 at 22:16
  • Am I right in saying if I was to implement client certs then I wouldn't even need an "auth" token at all? – James Sep 06 '12 at 10:54
  • @James: yes. With SSL with client certs, no need to do anything else with regards to authentication. With SSL without client certs, client must send a "password" (a secret string also known by the server) within the SSL tunnel, in the beginning of the conversation (e.g. as a HTTP header if your SSL happens to be HTTPS). – Thomas Pornin Sep 06 '12 at 12:33
  • In my scenario I have SSL, but no client certs. So I need to send this "API" (or "password") key to the client. I keep a copy of this stored at the server and for every request made by a client they sign it using the "API" key and the server can use that key to lookup the client & then validate the request. The only security risk I see here is I need to store the API key on the client somewhere (mobile app) which could *potentially* be extracted and re-used? – James Sep 06 '12 at 12:51
  • @James: oh yes. Whoever knows everything the client knows can do everything the client can. Which is why you (wisely) want to make a per-user API key: at least, you can remove access for a given key, if it turns out to be misused. It is a containment feature. To avoid this problem, do not store the key in the mobile app; instead, store it in the brain of the human user (i.e. make it a true password); but this implies that the human user will have to type the password regularly, and he will probably not like it. – Thomas Pornin Sep 06 '12 at 13:53
  • So really I need to either sacrifice some security for usability or vice versa. I guess the other option would be to try get the balance right i.e. invalidate API keys often to force the users to re-authenticate their credentials and generate a new key. How does using client certs mitigate this problem though? Wouldn't it be the same issue if the client has the certificate on the device, couldn't that itself be extracted and used? – James Sep 06 '12 at 14:05
  • 2
    what do you make the following [approach](http://stackoverflow.com/questions/11775594/how-to-secure-an-aspnet-mvc-web-api/11782361#11782361)? – James Sep 08 '12 at 12:19
  • If you are using SSL/TLS, (and if you aren't, you may as well write the password on the wall) you don't need a MAC function of your own. SSL/TLS guarantees message confidentiality and integrity. So your API key only needs to be some unguessable secret. You might use a crytptographically secure random number generator to create a number less than, say, 2 billion. Or any of the other secure password generator options. And absolutely do not use the user key as a apikey. You'll want to be able to revoke and reissue keys. – Elroy Flynn Aug 20 '16 at 14:24