I would like to implement an API key system to secure API calls to my app.
The way I think will work is my having a private key/secret per account. Each request contains the time, account id and a hash(time+secret).
The server can then do the same thing with the users secret from the database and check that against the hash the client sent.
Is this a reasonable way to do it? It is open to a brute force attack, but I'm thinking that as long as the secret is long (ie uuid) it shouldn't be too much of a problem...
A Thought
Any one could submit another request with the same time and hash and have it accepted, after all its valid, right?
The problem being that the nonce + hash can be replayed. A real authentication protocol requires at least two messages:
Server Client
---->challenge --->
<----response------
For example, the challenge could be the nonce, supplied by the server, and the client's response would be the hash of password with the nonce.
Unfortunately, this requires state, and the whole problem with RESTful protocols is that they do not want the hassle of keeping state. And yet they want to authenticate...
So you really have three options:
Option 1: Pretend the problem does not exist, and use the stateless "authentication" protocol. This is no different from using a cookie. The nonce + password-hash is no more secure than a cookie. Cookies can be stolen, etc, and replayed. The entire web is now plagued by these replay attacks.
Option 2: Try to bolt an authentication protocol onto a stateless communication method. Here, you would have the client send you a UTC time-stamp instead of a nonce. The use of the time-stamp provides limited defense against replay. Obviously your clock is not going to be synched with that of the client, so your server will allow any timestamp within some error margin, and that error margin will be the replay margin of the authentication protocol. Note that this violates REST, because the authentication message is not idempotent. Idempotent implies "can be successfully replayed by an attacker".
Option 3: Do not try to bolt an authentication protocol onto a stateless protocol. Use SSL. Use client certificates. Instead of having the client download a string, let them generate a certificate, or you can supply them with a key-pair. They authenticate via SSL and do not authenticate in your REST layer. SSL has lots of "overhead". It is not lightweight, precisely because it does address these replay issues.
So at the end of the day, it depends on how much you value access to your APIs.