OAuth timestamps and nonces
Tagged with: [ nonces ] [ oauth ] [ replay-attack ] [ timestamps ]
Oauth is a very popular authentication mechanism used for a lot of web applications. And not without good reasons. It is relatively easy to implement, has different flavours (2-legged, 3-legged system) so you can use almost anywhere that requires authentication and authorization. This post is not about how to implement oauth. That can be found in much greater detail than I can explain here, but about two tiny details that can make or break your oauth security: the oauth nonce and timestamp.
Signed requests
OAuth uses the concept of signing to make prove that the request actually came from you. It basically collects all the parameters from your request, adds some secret key to it, turns it into a hash and sends the request, including the hash. The other side, the provider, can look up the secret key that you uses (shared secret), create the same hash you did on your system and compare his hash with the one you have send. Anyone who want to change your request would be out of luck, since they cannot generate a correct hash (since they don’t know the secret key).
Now, normally, this would be enough, except we have a little problem we cannot solve and that’s called a replay-attack. This means that the same request is resend (maybe over and over again). Sometimes this does not matter but sometimes it does. For instance, when you POST a request which updates your bank account for instance.
Oauth has a simple, yet effective, system to combat these replay-attacks. First off all, you need to send a timestamp with your request. This is a number in seconds since 1-1-1970 (epoch). Secondly, you need to send a nonce. This is a “number used once”, and does exactly what it says on the can. It’s a number that can only be used once.
On every request you need to make you must make sure that the nonce you use it not already used in the same second. If you do, a server should (and will) deny the request. This means that somebody else who want to replay the request will be denied by the server. It’s not possible to either change the timestamp or the nonce used, since these values are also used in the signature. Changing them will invalidate the signature and the server will deny the request anyway.
Implementing nonces in your code
I hope you realise it’s a good idea to implement timestamp and nonces in your oauth code, but there are a few things you need to take care of. First off all, you have to be absolutely sure that the request you make has a unique nonce. The easiest way might be a counter that increments on every request you make (the nonces are not secret so they don’t have to be random or unpredictable). However, trying to take the easy way out by using a rand() can get you into trouble: you cannot be sure that rand() doesn’t produce the same value twice, and those values could be produced in the same second, which means you get 2 equals nonces in the same timestamp. It’s a thing that’s very hard to debug as well if you don’t have the correct logging. But on the whole, from a consumer standpoint, it’s fairly easy to implement timestamp and nonces without any real problems.
On the other side
But more and more developers nowadays are creating webservices. Which brings us to the other side of the oauth-request. The server side must somehow figure out which nonces for which users on which timestamps are used. Storing this data in a database will get you into trouble quickly. Too much data, slow indexing, everything will grind to a halt after colleting a few days of data. Another way would be storing it into (shared) memory. But still, it’s a lot of data and memory is limited.
Another way is store only the timestamp/nonces/user data for a certain amount of time. Let’s say a half hour (1800 seconds). This is a standard feature in almost every caching system available to php-programmers (normally called the TTL, or time-to-live). But storing your data for only a half hour will not stop replay-attacks. The attacker just waits an hour or so before sending the request again, so it knows that you don’t have the nonces for that particular timestamp anymore which means your server would just accept the request.
In order to combat this, we can limit which timestamps we accept in an oauth request. Let’s assume the current time is T, we could accept only request with timestamps between T-60 and T+60. This also mean we don’t need to save a half hour, but merely a few minutes now. This fixes the problem of storing too much data.
But it brings us to another problem: it means that the user who sends the request MUST use the timestamp we use on our server. If my computer’s clock is off by an hour, we are sending a timestamp of T-3600, which isn’t going to be accepted by the server. It’s mandatory that both server and consumer uses the same timestamp. Solution for this would be something like NTP, which syncs your computer with the time from atomic clocks. Now, because not every computer will be synchronized exactly (my computer might be of a few seconds from your computer), and because it takes time to send a request from A to B, make sure your don’t narrow the bandwitdth of accepting timestamps too much. Don’t use T-1 to T+1, because you will deny a lot of (valid) requests because of slow internet. You can log the differences between your consumers and your times and narrow or broaden the bandwidth if you need to.
Conclusion
Using Oauth is wonderful system, but as with everything you need to take care of what you are doing. Simple solutions like checking timestamps and nonces are a very good way of securing your system against replay attacks, but you have to implement it correctly. Not implementing trivial things like thing can (and most of the time will) result in a false sense of security.