Signing URLs Using HMAC or OpenSSL

I am interested in the signature of the signature (for example, http: //.../? Somearg = value & anotherarg = anothervalue & sig = aSKS9F3KL5xc ), but I have several requirements that left me without a solution.

  • I will use PHP or Python for the pages, so I will need to sign and verify the signature using one of two.
  • My plan was to use the priv / pub key scheme to sign some data and be able to verify that the signature is valid, but here, where it gets complicated:
  • Data is not known during verification (it is not just somearg=value&anotherarg=anothervalue )

My first instinct was to use OpenSSL, for example. using the RSA key pair, do something along the signature lines: openssl rsautl -sign -inkey private.pem -in sensitive -out privsigned and check only based on the privsigned data and the key: openssl rsautl -verify -inkey public.pem -in privsigned -pubin .

Using PHP openssl_get_privatekey() and openssl_sign() greatly simplifies the data, but I need to know (decrypted!) Data to check (which I wonโ€™t have): openssl_get_publickey() and openssl_verify($data, $signature, $pubkeyid); from http://php.net/openssl_verify .

Or am I missing something?


So, I looked at HMAC, but although many hash functions are available in both Python and PHP , I am confused about how I would have made a hash check . PHP hash_hmac() allows me to create a hash using a "key" (or in this case a string key). But how can I verify that the hash is valid (i.e. &sig= not just manually entered by the end user &sig=abcdefg1234 .

So, to summarize (sorry for the long question): How can I verify that the signature / hash was done using my server (cert / string) (if I cannot verify by redoing the hash of this data)? And do you have any preferences as to which route I should choose, Priv / pub-key or HMAC?

Any pointers big or small are very much appreciated! Thanks in advance,

  • Josh
+8
url hmac verification private-key signing
source share
3 answers

HMAC is a symmetric algorithm, so there is no separate algorithm for creating and checking. To check, you simply calculate the hash since it had to be initially computed, and make sure the result is equal to what you really received from the client. Security depends on an HMAC key that exists only on your server.

Unless you need signatures that can be verified by someone who does not know the secret key, HMAC is probably a better choice than public key systems for performance reasons. It may take several milliseconds to create or verify a public key signature (several years ago I calculated one implementation for 15 ms per operation), while HMAC is pretty fast.

(Oh, and you cannot verify any signature without knowing the data that it must sign. It makes no sense, as far as I see).

+5
source share

As Henning Maholm noted, HMAC is a better choice than a public key. There are several best practices that you should consider in your specific scenario that will affect your choice:

  • Do you want to consider the host name and scheme (http / https) in the signature? May be.
  • Do you want to consider the path in the signature? Maybe.
  • Do you want to consider the query string in the signature? Maybe.
  • Do you want to normalize the order of arguments and escaping before signing? Usually not.
  • You want to insert signature time, etc. (to create time-limited URLs)?
  • Do you want to associate the signed URL with some other user state like cookie?
  • Do you use user-generated or user-visible content directly in the HMAC? If so, you should โ€œsaltโ€ the key using a value that is randomized for each request.

When calculating the signature, you will need to encode it by the URL (base64 and base32 are popular options) and select the HMAC algorithm (for example, SHA-256) and decide how many bits of the signature you want to keep (trimming the HMAC value in half is usually safe). If you choose base64, beware of the different alphabets used according to URL safe versions other than url-safe.

Here is the implementation of the pseudocode (without checking errors or salting, etc.) for signing the line + request:

 const secret = ...; def sign(path, querystring): return path + "?" + querystring + "&sig=" + url_encode(base64_encode(hmacsha256(secret, path + "?" + querystring).truncate(16))) def verify(path, querystring): querystring_without_sig = remove_query_parameter(querystring, "sig") sig = base64_decode(url_decode(get_query_parameter(querystring, "sig"))) if hmacsha256(secret, path + "?" + querystring_without_sig)[:16] != sig: raise "invalid sig" 

HMAC SHA256 is recommended and available in all common languages.

Java:

 Mac mac = Mac.getInstance("HmacSHA256"); mac.init(secret); return mac.doFinal(value.getBytes()); 

Python:

 hmac.new(secret, input, hashlib.sha256).digest() 

PHP:

 hash_hmac("sha256", value, secret); 
+8
source share

If you want to use HMAC and Python, then:

$ pip install ska

Client side

 from ska import sign_url signed_url = sign_url( auth_user='user', secret_key='your-secret_key', url='http://e.com/api/' ) 

The URL generated is as follows.

http://e.com/api/?valid_until=1378045287.0&auth_user=user&signature=YlZpLFsjUKBalL4x5trhkeEgqE8%3D

Server side

Please note that the request.GET example below is an example. This will most likely be different from what is used in your structure (if you are not using Django).

 from ska import validate_signed_request_data validation_result = validate_signed_request_data( data = request.GET, # Note, that ``request.GET`` is given as example. secret_key = 'your-secret_key' ) 

Validate_signed_request_data creates a SignatureValidationResult object, which basically contains two properties:

  • result (bool): True if the data is valid. False otherwise.
  • reason (list): A list of lines indicating validation errors.
0
source share

All Articles