Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Securing a session-less RESTful API endpoint

I've created a simple RESTful API for a project partially following this very good blog post by Riyad Kalla. Now, I've read dozens of similar questions on Stack Overflow but I can't seem to find an answer to my security question.

Briefly, my requests go like this:

  1. The client has a public API key (plain-text, accessible to anybody sniffing the network traffic or properly checking the code source)
  2. The client sends a request to the server with the public API key
  3. The server has a secret API key (secret to anybody but the developer)
  4. The server creates a HMAC-SHA1 hash composed of the client's request data and the secret API Key
  5. The server sends a request identical to the client's request to the API server, but including the resulting HMAC-SHA1
  6. The API server looks up the secret API key in its database based on the public API key it receives
  7. The API server recreates a HMAC-SHA1 hash using the same data as the developer's server
  8. If the hashes match, the request is considered valid and is processed normally

I'm concerned that somebody using my service could fetch the public API key (by sniffing network traffic let's say), and then simply cURL the same request the client would originally do via their browser using AJAX directly to the developer's server. Therefore, the malicious user could be authenticated as a legit user and access the API with somebody else secret API key.

I'll try to give a concrete example. Normally I would do:

  1. AJAX a get request to my server.
  2. My server hashes my request with my API secret and send it to the API server.
  3. The API server validates my request and returns the payload.

But I'm scared that:

  1. Dr. Evil will sniff my public API key.
  2. Dr. Evil will cURL a get request to my server using my public API key.
  3. My server will hash Dr. Evil's request with my API secret and send it to the API server.
  4. The API server validates and returns the payload to complete Dr. Evil's vicious plans.
  5. Dr. Evil laughs an evil laugh.

Anything I'm missing or is this just part of the RESTful API game?

UPDATE: I am voluntarily omitting any form of timestamp validation to keep things simple and just focus on the authentication issue.

UPDATE 2: I've added a $_SERVER['HTTP_REFERER'] validation to the process. The goal here is that the client must send a referrer along with the request and it must match the referrer listed in the database on the API's side. Unfortunately, HTTP referrers can be faked easily. It is yet another level of security, but still not perfect.

UPDATE 3: I've changed my server side code to set the referrer to the remote IP address. This forces every request sent to my server that wants to be hashed using the secret API key ultimately get to the API server with the original request IP address. This IP can then be validated and the request can go through. I believe it is yet possible to fake $_SERVER['REMOTE_ADDR'], but it is more complex than faking $_SERVER['HTTP_REFERER']... Still not perfect I guess.

UPDATE 4: According to these posts: How to fake $_SERVER['REMOTE_ADDR'] variable? and https://serverfault.com/questions/90725/are-ip-addresses-trivial-to-forge, faking the $_SERVER['REMOTE_ADDR'] is possible though difficult. It is, however, impossible to receive a response from the faked request since you're not in control of the faked network. The request can be validated successfully but will its response won't fall unto malicious hands.

like image 558
Rémi Breton Avatar asked Jan 14 '13 18:01

Rémi Breton


1 Answers

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.
like image 72
datasage Avatar answered Sep 30 '22 20:09

datasage