34

first of all: I am quite unsure about the title of the question, so if you have a better idea, please feel free to tell (:

I would like to know about best-practise examples where services (like Twitter or co) which offer APIs and want you as a developer to use some API-Key prevent third parties from getting that key.

I will explain my regards with bad examples:

As far as I know, Twitter and FB require you to use API-Keys for API-requests. That's fine for server-side applications, but as soon as you submit your key from a web-app or desktop-application, the key is visible to others.

Because you have to submit that key, it doesn't make much sense to super-securely store it inside your app. For the request, it has to be plain.

One thing you might do is to host your own web-service or wrapper which appends the key server side and then routes that request to the target server.

But this is not possible if Twitter/or whatever service you are using is limiting API-requests per IP or want's to create IP-based statistics.

So to sum it up: If I was in the position to create an API for others and don't want them to use SSL, what possibilities would I have to make sure their key is safe and can not easily be stolen?

Xiong Chiamiov
  • 9,384
  • 2
  • 34
  • 76
user510083
  • 451
  • 1
  • 5
  • 5
  • 6
    Why wouldn't you use SSL? (There's a myth out there that SSL is bad for performance. In reality, the myth is outdated and no longer terribly accurate. [SSL imposes little performance overhead, in many realistic settings](http://www.imperialviolet.org/2010/06/25/overclocking-ssl.html).) – D.W. Aug 15 '12 at 00:36
  • The client-application would need to support SSL and depending on the dev-enviroment it can get very hard for the developer to meet the APIs requirements – user510083 Aug 15 '12 at 00:49
  • 1
    *"The client-application would need to support SSL"* - That does not sound like a barrier to me. Just about every platform I've ever seen makes it easy to use SSL, e.g., by using a `https:` style URL or by using an existing library. Doesn't sound like a good reason to avoid SSL to me. *"it can get very hard for the developer to meet the APIs requirements"* - I didn't follow what you meant by this, sorry. Do you want to elaborate? What API are you talking about, and what requirements did you have in mind? – D.W. Aug 15 '12 at 00:54
  • For web browsers, see also [REST authentication and exposing the API key](http://stackoverflow.com/questions/5472668/rest-authentication-and-exposing-the-api-key) on Stack Overflow. – Arjan Oct 17 '14 at 23:34

1 Answers1

37

The best practice is:

The basic idea. Create an API key (a 128-bit symmetric key) for each separate user account. This key needs to be securely stored on the server, and also securely stored on the user's client.

For each request made by the client, add an extra request parameter that has a "signature" on the entire request. The "signature" should be calculated as S = MAC(K, R), where K is the API key and R is the entire request, including all request parameters. Here MAC should be a secure message authentication code algorithm, such as AES-CMAC or SHA1-HMAC.

It is the client's responsibility to compute the signature and append it to the request; it is the server's responsibility to verify the signature and ignore any request with an invalid signature. You may also need to include an additional parameter with the request that identifies the user account making the request.

This will provide authentication of the request, but not confidentiality or replay prevention, and the client does receive an authenticated response from the server.

I suggest sending all requests over https (not http). This will provide an additional level of security against a number of tricky cases. The performance implications of doing this are less than you might think -- SSL has less performance overhead than most people think -- so don't discard this idea on performance grounds unless you've actually measured the performance overhead and found it to be unacceptable.

Additional things to watch out for. You may want to use a one-time-use nonce, to prevent replay of authenticated requests. I suggest using a cryptographic-strength random value (at least 64 bits long). This is unnecessary if you are using https.

Make sure your server is written to defend against host-parameter pollution (HPP) attacks. For instance, it should reject any request with multiple request parameters of the same type (e.g., http://example.com/foo.html?name=x&name=y). Also, when writing server code, be careful when creating new requests based upon a request you received. For instance, before processing each request, your server code might validate that the request comes with only the expected list of parameters and nothing more; discard duplicate parameters or unexpected parameters before processing the request.

Watch out for concatenation flaws if you decide to protect multiple values with the message authentication code.

D.W.
  • 98,420
  • 30
  • 267
  • 572