How to add content verification using hmac in PHP

Standard

Many times a requirement arises where we are supposed to expose an API for intended users, who can use these API endpoints to GET/POST data on our servers. But how do we verify that only the intended users are using these API’s and not any hacker or attacker. In this blog post, I will show you the most elegant way of adding content verification using hash_hmac (Hash-based Message Authentication Code) in PHP. This will allow us to restrict possible misuse of our API by simply issuing an API key for intended users.

Here are the steps for adding content verification using hmac in PHP:

  • Issue $private_key and $public_key for users allowed to post data using our API. You can use the method similar to one described here for generating public and private keys.
  • Users having these keys can now use following sample script (hmac-sender.php) to submit data:
            // User Public/Private Keys
            $private_key = 'private_key_user_id_9999';
            $public_key = 'public_key_user_id_9999';
    
            // Data to be submitted
            $data = 'This is a HMAC verification demonstration';
    
            // Generate content verification signature
            $sig = base64_encode(hash_hmac('sha1', $data, $private_key, TRUE));
    
            // Prepare json data to be submitted
            $json_data = json_encode(array('data'=>$data, 'sig'=>$sig, 'pubKey'=>$public_key));
    
            // Finally submit to api end point
            submit_to_api_end_point("http://yoursite.com/hmac-receiver.php?data=".urlencode($json_data));
  • At hmac-receiver.php, we validate the incoming data in following fashion:
            function get_private_key_for_public_key($public_key) {
                    // extract private key from database or cache store
                    return 'private_key_user_id_9999';
            }
    
            // Data submitted
            $data = $_GET['data'];
            $data = json_decode(stripslashes($data), TRUE);
    
            // User hit the end point API with $data, $signature and $public_key
            $message = $data['data'];
            $received_signature = $data['sig'];
            $private_key = get_private_key_for_public_key($data['pubKey']);
            $computed_signature = base64_encode(hash_hmac('sha1', $message, $private_key, TRUE));
    
            if($computed_signature == $received_signature) {
                    echo "Content Signature Verified";
            }
            else {
                    echo "Invalid Content Verification Signature";
            }
    

Where to use such verification?
This is an age old method for content verification which is used widely in a variety of applications. Below are a few places where hmac verification finds a place:

  • If you have exposed an API for your vendors to submit requested data
  • If you are looking to enable third party applications in your website. Similar to developer application model of facebook.

Hope you liked the post. Do leave your comments.
Enjoy!

  • Pingback: Abhinav Singh’s Blog: How to add content verification using hmac in PHP | Development Blog With Code Updates : Developercast.com()

  • Pingback: Abhinav Singh’s Blog: How to add content verification using hmac in PHP | Webs Developer()

  • http://beebo.org/ Michael Stillwell

    Where did you get the private key/public key terms from? I think they’re a bit misleading here in that they suggest encryption is involved, whereas HMAC is only involved in signing. They also suggest some mathematical relationship between the two, though they just random numbers. Neither the HMAC page on wikipedia, the HMAC RFCs, or the NIST paper use those terms. It seems more conventional to use “key” where you use “private_key”, and “digest” where you use “public_key”.

    • http://abhinavsingh.com Abhinav Singh

      Yeah right Michael, these public and private keys terms might be misleading. But the intent was to tell what key is shared and what not. Yup you can call them by what ever name you feel like :D

  • CJD

    Thanks for the post, very useful!

    One question, would the above be acceptable (security wise) for securing a web service that allows the editing and deletion of data?

    • http://abhinavsingh.com Abhinav Singh

      You can couple it with IP restrictions if the intended users are having static IP. Otherwise as far as $private_key is not exposed, attackers will not be able to enter your system.

      Also if you visualize $public_key=$username and $private_key=$password you can do more by simply using hmac technique.

  • Pingback: uberVU - social comments()

  • http://derschreckliche.1on.de derschreckliche

    Using “real” private and public keys like in terms of an asymmetric encryption would allow you to not need to store the “private key” on the server (as it should be private to the client).
    See
    http://en.wikipedia.org/wiki/Public-key_cryptography and especially
    http://en.wikipedia.org/wiki/File:Public_key_signing.svg for details.

    But in a scenario like this your solution works great.

    But there is one point i don’t understand: why do you need 2 keys for this?
    You could map a username to a (in your case called private) key on the server. So as the client is the only one knowing his (you would call it private) key – except to the mapping on your server. So you don’t need to send a key – and so don’t need a second one…

    • http://abhinavsingh.com Abhinav Singh

      Hi,

      I didn’t get your solution above. We map username on server as $private_key. But still when a user wants to drop data, I would like to know from whom it came from for content verification in the code. And hence I extract $private_key mapped to the passed $public_key by the user.

      “So you don’t need to send a key – and so don’t need a second one…” – How will this help?

    • http://derschreckliche.1on.de derschreckliche

      OK,

      my first point: i would rather use real public/private key pairs – so you can do authentication and encryption if needed.

      my second point: when using such “random” private/public keys you don’t need a second key if you map usernames to keys (not users public keys to private keys) on the server.
      only the username, the message and the signature needs to be transmitted (no key).
      as you know the user on the server you can authenticate him by checking the signature using the (“private”) key mapped to his username.
      So no second “public” key is needed.

      But like i mentioned in “first”, using real public/private key pairs would be a better idea.

  • Pingback: How to add content verification using hmac in PHP | Abhi's Weblog | Coder Online()

  • http://2000grad.com/blog Henrich C. Pöhls

    Dear Abhinav,

    I just found your interesting post, and wanted to tell you that I disagree with the terms you used.
    You named it “content verification”, however as I understood it, the content is not verified, but a user/client is authenticated. So I would suggest the term “user authentication”.

    Although you involve the parameter $message in the “signature” creation and verification, you are not interested in verifying the data in $message, but rather the user who’s key is used to be tied to this data. I suggest you use the term data instead of “content”.
    I also second the comments made earlier on public-key-crypto, again this is merely a terminology problem here.

    Otherwise, useful, if you do not have problems with replayed messages (i.e. I capture a legitimate msg, with a signature, and then send this same message again, and again at later times.)

    Best Regards,
    Henrich C. Poehls

    • http://abhinavsingh.com Abhinav Singh

      Hi Henrich,

      I will say though $private_key and $public_key might confuse you for something related to encryption, but this approach is still a content verification.

      Internally we are not interested in knowing which data was dropped by a certain user. All we want is to make sure is that, only the intended users have dropped the data. And yes that’s the only intention here. Hence its content verification.

      But yes this technique is used widely in modified form to serve various purposes. You might be using many such services in your day to day life.

  • Pingback: খবরাখবর: ডিসেম্বর ১০ « পিএইচপি, বাংলায়()

  • Pingback: vivanno.com::aggregator » Archive » Vérifier un contenu avec hmac()

  • http://alheim.7el.net alheim

    Interesting blog post.

    SHA1 encryption method is used in Oauth (http://oauth.net) and is very powerful to sign http requests.

    I agree with the terms public and private keys because they just ARE public and private keys.
    In oauth, for example, the public key is sent through the headers and the signature is decrypted with it and the private key. This private key is never sent through the network.

    To conclude, I confirm that we talk about content verification. This method is often used to avoid “man in the middle” attack.

    • http://2000grad.com/blog Henrich C. Pöhls

      Dear Abhinav,
      dear alheim,

      I am coming back to see that you replied, and I am sorry to be picky on words again, but first things first:
      You write “we are not interested in knowing which data was dropped by a certain user” and “only the intended users have dropped the data”
      Hence I argued you are not verifying content (ie. the data that a user drops), you say you are not interested. Thus, I argued that you are not verifying the content but the user.
      For users the latter is called user authentication and your “intended users” then become authenticated users and thus authorized users.
      Read any book on IT-Security for a definition of the terms. I do not want to diminish your work, the idea is good, and its fine that you do not want to verify content, and thus its fine that you do not offer a method to verify the actual content.
      Just your argument: “Hence its content verification” seems to me from an IT-Security point of view wrong.

      Second, please do not confuse symmetric and asymmetric encryption, and last but not least:
      SHA1 is not an encryption method, it is a cryptographic hash function, and thus it is something completely different.

  • http://www.zoombits.de/handy-zubehoer/bluetooth-headsets bluetooth kopfhörer

    It seems that the method is more about securing the content through cryptography technique that deals with public ans private key including SHA1 algorithm. Although it is still a good one to solve the intent.

  • tom

    1 – to prevent key tampering, append the public key to the data and sign the concatenated string.

    2 – to prevent replay, concatenate a timestamp to the data and sign the concatenated string.

    both are standard attacks.

  • dvh

    Why not just use cookie and https?

  • Pingback: Securing a javascript client with hmac - Tech Forum Network()

  • Pingback: Securing a javascript client with hmac - PHP Solutions - Developers Q & A()