What is the best way to implement "remember me" for a website? [closed]
Asked Answered
K

4

551

I want my website to have a checkbox that users can click so that they will not have to log in each time they visit my website. I know I will need to store a cookie on their computer to implement this, but what should be contained in that cookie?

Also, are there common mistakes to watch out for to keep this cookie from presenting a security vulnerability, which could be avoided while still giving the 'remember me' functionality?

Koroseal answered 28/10, 2008 at 21:9 Comment(4)
Check #1049 (part II of top answer)Harlie
if you are using ASP.NET, check out codeproject.com/Articles/779844/Remember-MeSlovakia
There is some very useful info over in Security SE ~ security.stackexchange.com/questions/19676/…Blenheim
The currently accepted answer by splattne is overly complex. Create a +16 byte token from a random source, hash it, and save the hash + account id in the database. Then send the token to the user (base64 encoded) in a HTTPS + httpOnly cookie (so Javascript can't access/steal it). This way, no one can guess the token or log people out with invalid guesses, yet even if your database is hacked no one can use the tokens in the database (they are hashed). So only the original client (or someone who steals the token from the browser store somehow) can use it.Burcham
M
577

Improved Persistent Login Cookie Best Practice

You could use this strategy described here as best practice (2006) or an updated strategy described here (2015):

  1. When the user successfully logs in with Remember Me checked, a login cookie is issued in addition to the standard session management cookie.
  2. The login cookie contains a series identifier and a token. The series and token are unguessable random numbers from a suitably large space. Both are stored together in a database table, the token is hashed (sha256 is fine).
  3. When a non-logged-in user visits the site and presents a login cookie, the series identifier is looked up in the database.
    1. If the series identifier is present and the hash of the token matches the hash for that series identifier, the user is considered authenticated. A new token is generated, a new hash for the token is stored over the old record, and a new login cookie is issued to the user (it's okay to re-use the series identifier).
    2. If the series is present but the token does not match, a theft is assumed. The user receives a strongly worded warning and all of the user's remembered sessions are deleted.
    3. If the username and series are not present, the login cookie is ignored.

This approach provides defense-in-depth. If someone manages to leak the database table, it does not give an attacker an open door for impersonating users.

Mcauley answered 28/10, 2008 at 21:9 Comment(45)
see also:#1049 you should NOT read the 'improved' versionMesseigneurs
The problem with this is that you expose the username in the cookie, though this is what Gmail does. Why do you need both a series ID and a token? Wouldn't a bigger token be fine?Frivolous
@yar: no it wouldn't be fine and the article describes whyTem
@yar: the article describes in detail. the series is being used to mitigate the results of a cookie theft.Tem
Also make sure that changing the user's password or password recovery information requires the original password. If the cookie is compromised, the attacker cannot prevent the original owner from accessing the account.Benison
can anyone explain when will the series identifier change? if never, then storing the username encrypted and the token will suffice?Grisham
the whole concept of the series identifier does not make sense as it is described here.Ideate
@altvali A new series identifier is issued when a valid username/password combination is presented to authenticate the user (instead of a token). This starts a new series of random tokens used to identify this particular (long) login session.Brainwork
@tvanfosson...why would you need this? Just generate a new UNIQUE token...there is no reason a single user could not have mutliple tokens...one for each login....Token A, Token B, Token C...there is no need for a series identifier.Ideate
Also, regarding this model, what it to prevent an attacker from stealing and than placing the cookie on his computer and deleting the cookie from the hacked computer. His computer would than be authenticated and updated as needed with out the hacked computer ever knowing? The only change would be that the hacked computers user would have to login again and set remember me. Whether or not the hacked user recognizes this would be uncertain.Ideate
You would need to add in computer characteristics..for uniqueness either a MAC address or a set of other characteristics like user agent, screen resolution, etc.Ideate
Isn't is more stable to use a ID instead of a username so you don't have to worry about any case sensitive and all the other problems that come with strings?Risa
I've posted a question about this answer: #10958084Flashbulb
@HiroProtagonist The Series Identifier is to prevent a DoS attack. Without it, I could quickly write a script hitting your site with every username and an invalid token, logging everyone on your site out.Flashbulb
Why not add a hash of the username instead?Lewis
If a new token is only generated in step 3.1, which only happens for a non-logged in user, wouldn't the new token be sent with every request of a logged in user? This leaves a lot of chances for a packet to be intercepted. Could this cookie be configured to only send when not logged in?Chirk
@Chirk set the path of the cookie to the path of the auto login pagePestilential
I implemented this solution yesterday and I think it works well, something that isn't mentioned is how to deal with 'orphaned' authentication informationin the DB. When the user manually clears his cookie cache, the authentication info in the database is orphaned. Perhaps implementing an auto update timestamp in the table and manually removing all authentication data over a certain age would be a good idea.Bissonnette
@ChrisMoschini Been awhile but I hope it's okay. Could you explain why a series identifier helps prevent Dos attack? Like HiroProtagonist, I don't see much difference between using a longer token and series identifier + token.Beaman
@Beaman If you just use a long token, and destroy all sessions for a user when any invalid token arrives, I can write a script that hits your site with every username and all 0's for the token to log all users out. Run it in a loop, no one can ever meaningfully login. If a valid Series token is required however before the server acts against sessions, the DoS attack is prevented.Flashbulb
@Yar the email id is included to maintain the uniqueness, since it can happen that the same token is generated for two different accountsCorkboard
@ChrisMoschini: Why would they be logged out? I only see that "remembered sessions are deleted", meaning that you could effectively DoS the rememberme feature but not the whole authentication, right?Darell
Improved version actually does not provide an extra level of security, only an illusion of it.As @Jens Roland claims, pretty much any attack vector that allows the user to steal the cookie also allows it to be deleted from the hacked computer.Lofty
Could you provide a simpler version with only username + token just in order to understand the basics ? (Then I'll be able to add the series)Inscription
If the user has a poor internet connection could this be an issue when receiving the new token? Example, user requests login with token, internet connection drops out, new token generated at server, new token not received by user, user tries again with old token, this is seen as a hack attempt and all tokens are removed from db, user now has to login againPraseodymium
Chrome sends a loading request when you type the URL in the address bar. This can cause the remember me code to execute prematurely which will invalidate the token by the time the real request is executed when the user presses enter in the address bar. I didn't see an easy way around this problem except to use a static cookie that doesn't change during subsequent logins. Anyone else encounter this problem?Dentilingual
This solution is WRONG, it does not handle cuncurrency: If two remember-me authentication request arrives at the same time, with the same remember-me cookie, the first one succeeds and changes the token, the second one causes an unsucceesfull authentication, and a false alarm (because the token has been already changed by the first request). (This situation can happen when the browser starts up, and the site is restored in two browser tabs.)Papilionaceous
In this case, race conditions are less important than preventing replay attacks. Race condition: Have to manually log back in. Replay attack: Tokens become more desirable to steal, since they are not a nonce.Skirl
Presenting a false alarm to the user is very undesirable. Whether it is because of reasons mentioned by slobo, craigrs84, or Frogga, this solution generates these false alarms routinely.Leprous
This question and answer are very weird. It's not mentioned if user id should be stored on a client and sent together with series and token for validation. So reader has to guess that series is probably a replacement for user. Second problem, question is closed, so only source of info are comments. Third problem: concurrency. And it's not small because opening same site in 2 tabs at once is very frequent. And you would not want it to fail even 1% of the time.Inviting
@Frogga one potential fix would be to store 2 tokens (previous and current) with each session in the db. If previous is received, that means current was not received and a new current is generated and returned. If current is received, current becomes previous and a new current is generated and returned. This however does not fix the above mentioned concurrency issues.Flashing
"A new token is generated" ..! Why? Why every time should I create a new cookie?Mend
Here's a golang implementation: github.com/janekolszak/remembermeSiderostat
The answer says "If the series identifier is present and the hash of the token matches the hash for that series identifier, the user is considered authenticated. " The series identifier isn't hashed so this makes no sense. I think what he's trying to say is "If the series identifier is present in the cookie, and the hash of the token in the cookie matches the hash of the token stored in the table alongside that series identifier, the user is considered authenticated. "Troll
As understand need to create hash for cookie name and value. Both write in mysql. At login page check if cookie with particular name (hash) exists. If yes, then select mysql where cookie name and value is the same as in mysql. If yes, then from mysql get user id and set sessions that user is logged in and id is mysql id. Am i correct? As understand cookie identifier is cookie name?Caterpillar
I am wondering why would I need 2 random numers insteed of single token? Is someone says SECURITY, then I would say, heck lets use 100 random tokents then.Marmara
You guys should read this article link, it tells us if a hacker accesses a victim's account, then the hacker has T_1, the victim has T_0, and when the victim access his account, he can know that someone accessed his account because he has T_0 (the unvalid token and the valid series).Scraper
Yo made the updates 444 :DAthabaska
"If someone manages to leak the database table, it does not give an attacker an open door for impersonating users" It does. But just until the user uses the site again. If someone steals series identifier and a token while the user is not accessing the site then it works like a charm.Cobnut
@Papilionaceous I was going to ask exactly the same question. You are totally right, if the user has two tabs open, the will get logged out from both tabs (even if he was authenticated in the second). I suggest that the token gets updated on every login or logout and not on every call.Numerator
@Cobnut it won't work though because when the user gets access to the database table, all they will get is the series and the hashed token. So if they created two cookies, one for each, the token will always fail because they've got a hashed version of the originalOccident
@ChrisMoschini how does the series prevent a DOS attack? What's to stop me from writting a script that tries all variations of the series cookie with the token just set to '1', it'll go through and log everyone outOccident
@Cobnut Not if you simply treat the RememberMe token as a password and only store its HMAC.Aubreir
Why not just IP based rate limiting? I get that hash_equals() will prevent timing leakage (which would take millions of requests to filter out network latency en server activity) but how is a 12char series lookup going to better protect you from DoS than a 64char token lookup?Seedtime
Just in case others were a little confused by @Jacco's comment - "you should NOT read the 'improved' version", here is my synthesis. I implemented the "updated strategy described here (2015)" but found that there were frequent false alarms about cookie theft (mentioned by other comments above). These happen due to concurrent requests (multiple tabs opening at once), poor internet (new cookie not updating), and Chrome's load pre-request. The changing token after each request is the problem. Just follow paragonie.com/blog/2015/04/….Assemblage
C
11

Store their UserId and a RememberMeToken. When they login with remember me checked generate a new RememberMeToken (which invalidate any other machines which are marked are remember me).

When they return look them up by the remember me token and make sure the UserId matches.

Contravallation answered 28/10, 2008 at 21:9 Comment(1)
This can be brute forced in seconds. I'll just set my user_id to 1 and brute force all tokens. It'll give me access in secondsOccident
B
10

I would store a user ID and a token. When the user comes back to the site, compare those two pieces of information against something persistent like a database entry.

As for security, just don't put anything in there that will allow someone to modify the cookie to gain extra benefits. For example, don't store their user groups or their password. Anything that can be modified that would circumvent your security should not be stored in the cookie.

Bremen answered 28/10, 2008 at 21:9 Comment(0)
C
5

Investigating persistent sessions myself I have found that it's simply not worth the security risk. Use it if you absolutely have to, but you should consider such a session only weakly authenticated and force a new login for anything that could be of value to an attacker.

The reason being of course is that your cookies containing your persistent session are so easily stolen.

4 ways to steal your cookies (from a comment by Jens Roland on the page @splattne based his answer on):

  1. By intercepting it over an unsecure line (packet sniffing / session hijacking)
  2. By directly accessing the user's browser (via either malware or physical access to the box)
  3. By reading it from the server database (probably SQL Injection, but could be anything)
  4. By an XSS hack (or similar client-side exploit)
Caren answered 28/10, 2008 at 21:9 Comment(1)
1. HTTPS is designed to prevent this. 2. Stay Logged In isn't the security problem here, you have bigger problems. 3. Same as 2. 4. This can be prevented by access-control policy and good input sanitation; if you don't take these steps, you again have bigger problems than Stay Logged In.Flashbulb

© 2022 - 2024 — McMap. All rights reserved.