Signing HTTP requests to make sure that the client is not an attacker (or bot)

If you are developing a mobile application or a firmware that will make HTTP requests, it is a good practice to implement a hashed signature to make sure, at the server side, that is really your application or firmware who is requesting.

A suggested process is as follows:

Define a secret key. This key will be in the server code and in your client code (preferably obfuscated).

KEY="This is your secret key"

The client creates a request including the signature and the data to generate the signature in custom HTTP headers. For example, the HTTP request will be:

+-------------------------------------------------------------------+

POST /endpoint HTTP/1.1
Host: domain.com
Accept-Encoding: gzip, deflate
Connection: Close
x-request-id: 1484010287
x-device-id: 05a18f38-c218-4d1c-a9d0-ac36763580e1
x-content-digest: YXNkZmhqa2xzZGZqa2w7c2RmamtsamtsamtsO2prbDthc2Rmamts
x-signature: YXNkZnNkZmFzZGZhc2RmYXNkZmVyeXRyanl5dWs5

Request body

+-------------------------------------------------------------------+

The custom HTTP headers start with "x-" (a good practice). As you see there are 4 custom headers:

  • x-request-id: A unique id generated by the client.

  • x-device-id: A device identifier.

  • x-content-digest: The request body digest. This is generated by hashing the request body and then encoding the result in base64 to make it "printable".

  • x-signature: The signature of the request. This is the trick, you create the signature by using HMAC (keyed-hash message authentication code). Concatenate the strings that will be changing all the time and HMAC them using the secret key and encode the result in base64 to make it "printable".

    signature = base64( hmac( x-request-id + x-device-id + x-content-digest, KEY ) )

At the server side at least 3 validations should be performed:

1.- Check for the existence of the custom headers.
2.- Digest the request body and check if it is equal to the value of the "x-content-digest" header.
3.- Create the signature and check if it is equal to the value of the "x-signature" header.

All those validations must succeed to accept the request.

Obviously, you should make your requests using HTTPS, but in the case that someone got the specs of your requests, this will be your last line of defense. Try to handle your secret key as an industrial secret.

You have to consider your resources because hashing functions are expensive. In this example I use HMAC SHA256 (HMACs are substantially less affected by collisions than their underlying hashing algorithms alone. Check this link).

I created a server side example in PHP and client side examples in C (you will need the development libraries of openssl and curl to compile it), an Android application and an iOS application (in Objective C). Download them from here.

You may also want to check the literature about JSON Web Tokens. They can be used in a similar way.