22

I read about many old questions about this argument, and I thought that the best practice is to set up a cookie with username,user_id and a random token.

Same cookie's data is stored in DB at cookie creation, and when users have the cookie they are compared (cookie data, DB data).

Sincerely I can't understand where is the security logic if this is the real best practice.

An attacker who steals the cookie has the same cookie than the original user :|

Forgotten some step? :P

Ayush Kumar
  • 833
  • 2
  • 13
  • 30
itsme
  • 48,972
  • 96
  • 224
  • 345
  • I'm not 100% sure what the state of things in PHP is to date, but typically the best practise is to use an existing well-regarded framework rather than roll your own. – Iain Galloway Aug 27 '11 at 12:15
  • Does codeigniter have an authentication module? Edit - Looks like a yes: http://stackoverflow.com/questions/346980/what-codeigniter-authentication-library-is-best – Iain Galloway Aug 27 '11 at 12:27
  • 1
    Possible duplicate of [What is the best way to implement "remember me" for a website?](http://stackoverflow.com/questions/244882/what-is-the-best-way-to-implement-remember-me-for-a-website) – Jonathan Hall May 07 '17 at 12:11

7 Answers7

53

You should NEVER EVER store a users password in a cookie, not even if it's hashed!!

Take a look at this blog post:

Quote:

  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]
  2. The login cookie contains the user's username, a series identifier, and a token. The series and token are unguessable random numbers from a suitably large space. All three are stored together in a database table.
  3. When a non-logged-in user visits the site and presents a login cookie, the username, series, and token are looked up in the database.
  4. If the triplet is present, the user is considered authenticated. The used token is removed from the database. A new token is generated, stored in database with the username and the same series identifier, and a new login cookie containing all three is issued to the user.
  5. If the username and series are 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.
  6. If the username and series are not present, the login cookie is ignored.
hakre
  • 193,403
  • 52
  • 435
  • 836
Danielss89
  • 863
  • 1
  • 11
  • 17
  • 2
    I assume the token is just a long, randomly generated alphanumeric string. But what is the series? I'm not sure I understand the nature of that value. Wouldn't username + token be enough? The article you link to no longer exists :-( – manuelflara Apr 17 '13 at 11:59
  • 1
    the "series" is used to notify the legitimate user that someone else already used the current valid token. you send the series1_token1 to the legitimate user, someone thefts the series1_token1 and he uses it. A new token is generated (series1_token2). Now the legitimate user generates a pageview and the system should notify that he is using an a token (series1_token1, which was overriden by the 2) that was used already by someone else. so series is used to group tokens together. –  May 04 '13 at 09:47
  • another note: if the legitimate user does two nearly contemporary requests (ajax, embedded images) the error could happen, even if you update the db row just before you send the setcookie(). meditate about this detail before implementing this. –  May 04 '13 at 22:44
  • A solution could be updating the sessionID only after, let's say, 5 seconds instead of doing it on every request. hth –  May 04 '13 at 22:51
  • I don't understand - this will not a user to have multiple browsers with the auto-login, right? – jdepypere Jul 17 '13 at 18:37
  • You don't need to put the username in the cookie. You can place some other random string that points back to the username. – Usman Mutawakil Oct 09 '16 at 07:53
  • What's to stop someone running a script that guesses a ton of random usernames and series logging everyone on your site out? – A Friend Dec 11 '18 at 06:55
20

You should store the user_id and issue a random token in addition to the user's password. Use the token in the cookie and change the token when the password changes. This way, if the user changes their password then the cookie will be invalidated.

This is important if the cookie has been hijacked. It will be invalidated if the user detects the hijacking, and furthermore because the token is unrelated to the password the hijacker won't be able to derive and then change the user's account password and "own" the account (assuming you require the existing password before changing passwords, the hijacker doesn't own the email account so they can't use "Forgot my password" etc).

Take care that the tokens aren't easily guessable (i.e. they should consist of entirely random data, like from a CRNG).

If you want to go one step further, you can encrypt the cookie before sending it and decrypt it upon receipt. And further to that, don't assume that a hijacker doesn't know the encryption key used, so validate the cookie's contents upon decryption.

But all that said, prefer to use a library's persistent session management instead of rolling your own.

ta.speot.is
  • 26,914
  • 8
  • 68
  • 96
  • 2
    You can easily invalidate random token if user changes password, so that is a poor reason. – nilskp Jan 18 '13 at 20:25
  • @nilskp But then you have to track the tokens issued, no? – ta.speot.is Jan 18 '13 at 20:40
  • 5
    Of course. But what you're proposing means exposing hashes of passwords, something hackers spend a lot of time trying to get access to, because you're not just exposing any old hash, you're exposing the very same hash that is stored on the server for validation. – nilskp Jan 18 '13 at 20:51
  • 1
    I agree with @nilskp. The best answer is the one from Danielss89 with the link to Jaspan's article. – benweet Jan 19 '14 at 13:23
5

I wouldn't even store the username in a cookie, just a random token generated with a near impossible to crack technique and map that to the user in your database, and never store user's password even hashed in a cookie, it will be open to Brute Force Attack. Yes if someone steal the token he can access user's account but the password will not be compromised and the token will be invalidated as soon as the real user logs out. Also remember that you shouldn't allow sensitive tasks like changing password to a user who just have a valid token, you need to ask for the password again for such tasks.

Community
  • 1
  • 1
nobody
  • 10,599
  • 4
  • 26
  • 43
3

if your cookies are stolen anyone can log into your accounts. it's actually what firesheep does. the security lies in the random token. the whole system assumes cookies can't be stolen. the only other way to get in then is to guess the random token. if you make it long enough it should be nigh-impossible.

doxin
  • 698
  • 1
  • 7
  • 22
0

The "step" that you seem to be forgetting is that if the cookie value is properly hashed it would be of a little value to an attacker.

EDIT:

Here's a couple of things you can do to protect your users against cookie theft related attacks:

  • Regenerate tokens over time, so that an attacker would not be able to impersonate a user unless she has a recent enough cookie. If security is top priority, regenerate tokens on each request (page load). If it isn't, regenerate tokens on password change.
  • Keep and validate hashes of user agents, so that an attacker would not be able to impersonate a user unless she has both the cookie and the user agent that of the user.

p.s. Cookies should hold (random) tokens and not password hashes (see Hashes or tokens for "remember me" cookies?).

Community
  • 1
  • 1
Emanuil Rusev
  • 34,563
  • 55
  • 137
  • 201
  • 4
    Hashed or not, the cookie value allows the attacker to impersonate the user. – ta.speot.is Aug 28 '11 at 01:14
  • This is an unavoidable fact. The best consideration to prevent this from happening is to use end-to-end encryption on any page which a 'remember me' cookie is sent on. – deed02392 Jan 27 '12 at 13:07
  • @Emanuil Rusev, as you have recently said: "Giving the cookie to an attacker is the equal in damage as giving him your password." – Haralan Dobrev Dec 20 '12 at 10:48
  • @HaralanDobrev, I wouldn't say equal, but I agree that there could be significant damage. I updated my answer to address the issue in more detail. – Emanuil Rusev Jan 21 '13 at 20:48
  • @ta.speot.is, This is correct. I updated my answer to address the issue in more detail. – Emanuil Rusev Jan 22 '13 at 19:20
-1

I always knew that the "remember me" feature only converted the session cookie (i.e. the cookie with the session ID) from expiring when closing the browser to a future date, it doesn't involve saving additional data, only extending the session.

And yes, if an attacker gets the cookie, it can impersonate the user. But this is always valid, and has nothing to do with "remember me".

Albireo
  • 10,977
  • 13
  • 62
  • 96
-1

My approach is the following:

  1. Hash the user_id
  2. Generate an unique key for the user - md5(current_timestamp)
  3. Save the key to the DB
  4. Encode everything so it looks like a BS - base64
  5. Save it in the cookie

So far, It has been working great for me :)

kapex
  • 28,903
  • 6
  • 107
  • 121
Stef
  • 203
  • 3
  • 4
  • `md5(current_timestamp)` is not a unique key, and it can be guessed by looking at the timestamp of the creation of the registration. How do you compare the key and the cookie? – A.L Oct 13 '14 at 08:29