1

I am currently working on a pet project website and I want to implement the "remember me" feature for logins and wanted to know if my procedure is secure. The authentication process basically goes something like this:

  • If a user want to be remembered and logs in successfully alongside his session cookie he gets a long-lasting remember-me cookie.
  • The cookie contains some random data(a UUID) and the user's id.
  • The UUID and a salted hash of the user's id get stored in a database.
  • When the user has to be reauthenticated from such a cookie, the user id from the cookie is checked against the hash from the database corresponding to that random data.
  • If they match, the user is logged in, the current id/hash pair is deleted from the database and the user gets a new one to give potential cookie thieves a narrower window. to act
  • Id/hash pairs older than 3 weeks get expired as well to further prevent cookie theft.

I would like some review of my method. Is this secure? If so, could it be implemented in any other, perhaps simpler, manner?

  • Why not keep it simple - generate a token ID using a CSRNG and store this random long string in the cookie only. On the back-end, this random long string is looked up and if there's a corresponding user ID for the record, the user is logged in and the sliding expiration is updated (both for the cookie and for the DB record). No need to add extra hashing or to store the user ID in the cookie itself. – SilverlightFox Aug 9 '14 at 13:35
  • @SilverlightFox Wouldn't an attacker with access to the database be able to simply generate a cookie of his own from those token/user-id records? Those tokens are equivalent to login credentials, isn't not hashing them really unsafe? – nikitautiu Aug 9 '14 at 18:48
  • If an attacker has access to the database, all bets are off. Your system is compromised. The reason you hash passwords is because if an attacker gets those then they are often used elsewhere and hashing protects them. The same isn't necessary for tokens. – SilverlightFox Aug 9 '14 at 18:53
  • I understand what you're saying, but at the same time I'd rather not consider "all bets off" when someone gets hold of my database. To me, storing a hash of the token seems too trivial of an operation not to do, especially given that it can prevent these attackers from posing as other users during the window of opportunity from when they get hold of the data to the "oh crap someone's looking at my database" moment. – nikitautiu Aug 9 '14 at 19:57
  • OK, fair enough. Often it is better to keep things simple, as complexity is the main enemy of security. What I should have said that yes, you can hash them, but there is no need to salt your hash per user because they are random tokens and rainbow tables wouldn't help an attacker. Simply store the value in the cookie and the hashed version of the value in the database (with maybe a static application level salt). Use a CSPRNG for the cookie value though. – SilverlightFox Aug 9 '14 at 20:01
4

You're overcomplicating the solution, and not really gaining much out of it. Others have gone over the flaws with your implementation, but I'll outline a better approach.

When a user chooses to have their authentication remembered across browser sessions, use a CSPRNG to generate a random 128-bit string. Send them this string, then hash it (SHA-2/256 is fine), and store the hash alongside the user record. When the user revisits your site, hash the token they've provided and look up the corresponding user record with that token. When a user explicitly logs out, delete the cookie from the browser and delete the hash of the token from the database.

I'd probably reissue tokens every time a user authenticated with one (e.g., they should be valid for one use only). And store the expiry date alongside the hashed token to ensure its maximum lifespan server-side.

  • You can use a fast hash here because there's no risk of rainbow tables or dictionaries being used due to the size of the key space. – Andy Boura Aug 10 '14 at 6:35
  • So you would say cookie theft is too much of an edge case to bother about? – nikitautiu Aug 10 '14 at 7:31
  • well when making sure each one can only be used once you have yourself secured against it because you could throw the session into oblivion if an old cookie gets noticed and inform the user. the only problem will be tabbed browsing if the user acts too fast. – My1 Aug 18 '18 at 11:57
3

Just because a UUID is highly likely to be unique doesn't mean that it's difficult to guess. Version 4 UUIDs contain 122 random bits, and I would recommend that or version 5 (SHA-1). Honestly, I usually use SHA256 or higher and a long string of concatenated random numbers. Then store the hashcode in both the database and a cookie.

There isn't much benefit to rehashing the long term token because an attacker that has database access likely doesn't need to steal sessions. I suppose it could mitigate corner cases in which the attacker has limited database permissions or the session is shared across multiple end points.

What is your salt? Are you storing it in the database? (bad idea) What exactly does storing the hashed/salted user id buy you? I don't think it's a vulnerability, but you should only need to store the long term session token (which might include the UUID/random number, a salt, and a username). When the user would otherwise get logged out, look up their current session in the database and compare the long term session column with the value in the cookie.

  • I added the salt wanting to prevent attackers from guessing the user id from multiple occurrences of it, but as @PlasmaSauna pointed out, it's pretty redundant in a scenario where the attacker already has access to the database. – nikitautiu Aug 9 '14 at 6:27
  • Also wanted to ask, what is the point of also storing a salt in the cookie, isn't that redundant already having a random number stored? – nikitautiu Aug 9 '14 at 6:30
  • 1
    If your UUID doesn't have enough bits of entropy then concatenating a salt before hashing would be a good idea. If your UUID has enough bits of entropy then you should be fine. SHA256 produces a 256 bit output, I like to use as many of those bits as I can. – glidersecurity Aug 9 '14 at 7:28
0

I'll echo glidersecurity's comment on UUIDs with a Wikipedia link: http://en.wikipedia.org/wiki/Universally_unique_identifier#Variants_and_versions

With your current solution (if I'm reading it correctly), if an attacker gets read-only database access, they only have to supply cookies like so:

foreach userID in the users table:
    foreach random_number in the remember_me_cookie table:
        try to start a session with userID+random_number

to brute-force an entry into your system.

  • If an attacker gets database access then all bets are off - they already have the data. An exception is password data itself - this is where salting and hashing is good because passwords may have also been used on other sites. – SilverlightFox Aug 9 '14 at 13:32
  • Whoops, I was thinking of a case where the attacker gets read-only access to the database (like with a stolen database backup that was somehow not encrypted), but didn't write that into my answer. Thanks! – PlasmaSauna Aug 10 '14 at 0:18
  • well if the account grants you access to some stuff not in the DB or whatever you might wanna make it so that plain read-only db access may not be enough to actually give enough access to get into a session. – My1 Aug 18 '18 at 11:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.