News Archive
PhpRiot Newsletter
Your Email Address:

More information

Quick and Dirty REST Security (or Hashes For All!)

Note: This article was originally published at Planet PHP on 15 May 2012.
Planet PHP

So in working up a new RESTful service I've been tinkering with, I wanted to provide some kind of aoauthenticationa system for it. I started to look into OAuth, but got a bit overwhelmed by everything that was involved with it. Looking for something a bit more lightweight (and simpler to implement a bit more quickly) I came across this older article with a suggestion of a private key/hash combination. I figured that could do the job nicely for a first shot, so I set to implementing it.

On the Server Side

I'm using the FuelPHP framework for this one, but that's really only giving me a structure to work in and pull the request information from. This would work in most major frameworks (and even outside of one if you you're a aodo it my waya kind of developer). First off, let's start with the controller side:

response('fail!',401); } else { // we have the headers - let's match! $user = Model_User::find()-where('public_key',$requestHeaders['X-Auth'])-get_one(); if ($user !== null) { $hash = hash_hmac('sha256',$request,$user-private_key); return ($hash == $requestHeaders['X-Auth-Hash']) ? true : false; } else { return false; } } } public function post_index() { // return the user details here.... } public function router($resource, array $arguments) { if ($this-validateHash() == false) { $resource = 'error'; $arguments = array('Not Authorized',401); } parent::router($resource,$arguments); } } ?

There's a lot going on here, so let me walk you through each of the steps:

  1. First off, we're making a RESTful service, so we're going to extend the Controller_Rest that Fuel comes with. It has some handy special routing. Our POST request in the example below would try to hit the aopost_indexa method and have its hashes checked in the process.
  2. Next up is the aovalidateHasha method - this is where the hard work happens:
    • The request and headers are read into variables for easier use ($request and $requestHeaders).
    • It then checks to be sure that both of our required headers are set (X-Auth and X-Auth-Hash). There's nothing magical about these header names, so they can be switched out depending on need and naming preference.
    • If they're there, the next step is to find the user based on the public key that was sent. This value is okay to openly share because, without the private key to correctly hash the data, your requests will fail.
    • The hash_hmac function is then used (with the aosha256a hash type) to regenerate the hash off of the contents of the request and the private key on the found user.
  3. If all goes well, the request continues on and the aopost_indexa method is used. If it fails, however, the check in the aoroutea method of the controller makes a switch. It changes the currently requested resource to ao/error/indexa instead of what the user wants. This seamlessly shows the user a aoNot Authorizeda error message (401) if the hash checking fails.

A Client Example

Now, to help make it a bit clearer, here's an example little script showing a curl request using the hashes:

You can see that both the public and private keys are specified (but on the PHP side, not visible to the user) and are sent as the aoX-Auth*a headers as a part of the request. In this case, we're POSTing to the &

Truncated by Planet PHP, read more at the original (another 733 bytes)