3

I have a situation in which I cannot use a server-side session, but must allow users to log in, and for their logged in state to be persistent between queries.

As with anything that involves crypto of any kind, I know how easy it is to make a mistake and just wanted some extra pairs of eyes to look over what I am proposing.

u = the unique, numerical user id
s = a global server-side secret composed of a long, random, alpha-numeric string,  64 characters or more

Upon login, I propose to set two cookies on the client.

  1. The User ID: u
  2. The Authentication Token: hash(u + s)

Upon subsequent requests, the server will use the given value of u and the known, secret value of s to calculate and compare against the given authentication token. If they match, this must be a valid user, right?

An attacker cannot generate an authentication token without knowing the secret, and so cannot generate a token for someone else's user account.

If I make the cookies relatively short-lived, an hour perhaps, and provide cookie-destroying logout functionality, even shared computers would be relatively secure.

The global secret s could be changed (perhaps by a daily cron-job) to protect against a long term brute-force on a known hash/userID pair.

Does this sound ok?

Edit:

In reading that through again, I realise the introduction of a timestamp would be very helpful. So a third cookie with the timestamp, and the hash would need to include the timestamp, the userID and the secret. Then a TTL could be set on the authentication token, and cookie expiry (which is not a remotely secure revocation method anyway) would no longer matter.

1 Answer 1

4

Your basic idea seems sound, but I'd recommend using HMAC instead of a plain hash. So the cookie sent to the client would contain three values:

  1. user ID u,
  2. timestamp t, and
  3. authentication token HMAC(s; [u, t]),

where s is the secret key and [u, t] is a string unambiguously encoding the values of u and t.

An obvious disadvantage of this scheme is that there's no way for a user to explicitly log out. Unfortunately, this flaw is inherent in any scheme that stores no per-user state on the server. As you note, making the tokens valid for only a short period will help to mitigate this issue, although I'd consider even an hour a fairly long period for such a purpose.

If you can rely on the user's browser running JavaScript, you could include a script that sends a background AJAX request to the server regularly to refresh the authentication cookie. This could let you reduce the validity period down to, say, a couple of minutes.

4
  • Thanks for your reply and input on the HMAC (I always forget about those things :P). So you don't envisage any problems in using a global key? I guess it's basically the same as a root certificate key and I'm just signing authentication tokens as if they were certificates right?
    – lynks
    Apr 24, 2012 at 22:18
  • In response to your edit: Does unsetting (or setting to null) the value of a cookie not securely remove it from the client machine? Granted if the client machine was infected the token could be captured, but that's out of my hands I think.
    – lynks
    Apr 24, 2012 at 22:25
  • Well, certificates are signed using public-key crypto, whereas MACs like HMAC are symmetric crypto primitives. (That is, the key needed to verify a MAC is the same as the one used to create it.) But other than that, yes, the situation is similar. Just make sure the secret key stays secret and you'll be fine. Apr 24, 2012 at 22:26
  • As for unsetting the cookie, it might make it impossible to retrieve on the client side, but I wouldn't necessarily rely on that. There's a general security principle there -- never rely on the client if you can avoid it. More specifically, I'm pretty sure that the cookie storage mechanisms in most browsers were never really designed with secure data wiping in mind. Apr 24, 2012 at 22:29

You must log in to answer this question.