Securing a session-less RESTful API endpoint Securing a session-less RESTful API endpoint curl curl

Securing a session-less RESTful API endpoint


You are on the right track by using HMAC. However, there are two additional things that will make your application more secure.

  1. Require a timestamp in the client POST, needs to validate within 5 min of the server time. It should also be included in HMAC generation. If someone tries to change this the HMAC signature would be invalid, unless they had the secret key to update the HMAC signature.
  2. Use SSL, with certificate validation. Prevents a man in the middle attack. Don't allow any non-ssl requests.


The solution I've found to stop other scripts from using a public API key and sending requests to the server-side HMAC-hashing script is to send the original requester's identity along with the request. I'm using $_SERVER['REMOTE_ADDR'] to determine the original requester's identity since it's harder to fake, and faking it usually means they won't get a response.

/* $this as a class that handles requests */// Build hash and include timestamp$this->vars['timestamp'] = time();$this->vars['hash'] = hash_hmac('sha1', http_build_query($this->vars).$this->vars['token'], API_SECRET);// Send request to APIcurl_setopt_array($this->curl, array(    CURLOPT_RETURNTRANSFER => 1,    CURLOPT_URL => $url,    CURLOPT_POST => $this->method == 'post' ? 1 : NULL,    CURLOPT_POSTFIELDS => $this->method == 'post' ? $this->vars : NULL,    CURLOPT_CONNECTTIMEOUT => 15,    CURLOPT_TIMEOUT => 15,    CURLOPT_REFERER => $_SERVER['REMOTE_ADDR'], // Referer here!    CURLOPT_MAXREDIRS => 3,    CURLOPT_HTTPGET => $this->method == 'get' ? true : false));

Once sent, the API doesn't only check the secret API key from the database, but it also checks if the $_SERVER['HTTP_REFERER'] is listed as allowed! This also allows the API to accept servers on a per-user basis.