4

I am building a REST API that will receive requests like:

GET /api/entities
GET /api/entities?filter=X&sort=Y

This seems straight forward: have the client HMAC(path + query, key), send me a key identifier and HMAC in a header or something, and then I do the same on the server to see if they match.

Here's my concern:

POST /api/entities

{ "foo": "bar" }

If the client computes the HMAC on that path and query, theoretically that HMAC could be used to submit any body.

tl;dr How would one properly implement request signing for GET, POST, PUT requests that may or may not have a JSON body?

Jason
  • 43
  • 1
  • 3

1 Answers1

4

You should HMAC the payload as well. Since you mentioned including a header with the HMAC of the path and query parameters, you could have a separate header that contains the HMAC of the body. However, you will likely only want one HMAC to be sent, so an attacker couldn't mix and match the different sections. Thus you could do something like this:

HMAC-Signature: HMAC( HMAC(path + query, key) + HMAC(body, key), key)

You may want to scrap HMAC all together and use TLS with client certificates. HMACs would be subject to replay attacks, unless you introduce nonces. Additionally, you have to consider that the HTTP spec can be hard to interpret consistently. Different browsers (and client libraries) have different approaches for things like character encoding. One application may want to send a?b=' but another may send a?b=%27, before decoding, these two resource/query strings will have very different HMACs.

amccormack
  • 3,971
  • 1
  • 15
  • 23
  • Thanks. I think client certificates will work. From what I can tell, I kill the authentication and integrity birds with one stone. – Jason May 21 '15 at 03:08