We are currently designing a REST API, and thinking about securing it.
Going through a lot of documentation, it has become clear that 2 options are available.
HMAC Authentication
By hashing with HMAC-sha1 a series of predefined elements with the secret_key, we sign the request. The verification is done by doing the exact same process server side and comparing the resulting hashes.
Our implementation goes like this:
- Getting current timestamp
- Creating HMAC:
hmac(full_url + request_body + timestamp + secret_key + token)
- Sending the signature as it:
clientId + hmac_signature + timestamp + token
The main advantage of this, is that the secret_key is never transmitted in the request, which prevents replay attacks mostly. But as a drawback we have to store the client credentials (secret_key) in a raw format in our database. And if our database gets compromised we might as well revoke all current API clients credentials.
HTTPS Authentication
Using SSL over our API will allow us to create a secure channel to exchange private information.
We basically send the same information without hashing it with HMAC.
Our design is going to be exactly like (or very similar to) the OAuth2 specification.
Comparing to HMAC this has many advantages as we delegate most of the job to SSL. And clients do not have to include a library for hashing like with HMAC. Finally our database is safe since client's secret_key will be securely stored.
But if someone successfully sniffs out one request, he could steal the secret_key and start to create his own requests.
Is there a way to use the advantages of HTTPS without sending clear credentials and without having to store clear credentials?
One of our alternative designs was using private/public key generated client side, and use it to exchange a key to encrypt secret_key for future requests. But not many browsers have this capability (<keygen>
) and it is quite an annoyance for mobile applications.