4

Every resource I find (I, II, III) about how to implement in a secure way the typical "remember me" login feature, recommends storing a user identifier and an associated unique token in the cookie, and then the hashed token associated to the user in the database. This way we are safe of:

  • User impersonation. Should we store remember_me_user_id=93 in the cookie, it would be quite possibly to log in as admin crafting a cookie with remember_me_user_id=1. Adding the unique token to the cookie prevents from that.
  • Timing attack. The user identifier is used to look up the user, so the time elapsed is indifferent because it is searching but not authenticating. Should we look up by the unique token, the time information could be used to craft a valid token character by character.
  • Rainbow attack. The token is stored hashed in the database, so if the table information gets compromised it is useless.

But what about if we just store the user identifier in a cookie signed using a server secret? As far as I see, it prevents from the very same kind of attacks:

  • User impersonation. The cookie is signed, so an attacker can't craft another valid one without the server side secret.
  • Timing attack. The cookie is signed, so the attacker can't create it step by step.
  • Rainbow attack. No token stored in the database, no worries.

And, as far as I see, it has the same dangers that the cookie with the token:

  • You have to trust that the browser will expire the token when the time arrives. Solution: Timestamp the cookie and compare the time in the server.
  • XSS attack. Solution: Mark the cookie as http_only.
  • Eavesdropping. Solution: Mark the cookie as secure and use https.
  • Having a long lived cookie which is able to authenticate a user is very dangerous. Mitigation: 1) Refresh the cookie and token at every X requests in a server token based solution (it will still last all the period if the user does not come back). 2) Refresh the cookie and extend its timestamp at every X requests in any of both solutions (then you are "remembering" for a shorter period if the user doesn't come back).

Is my rationing correct or am I missing something?

  • 2
    Consider the scenario where you want to revoke a specific session. In some cases you don't want to affect everyone. – Steve Apr 02 '19 at 16:45
  • Good point, that's true. But if it is not a concern, you get a simpler solution (less actors involved) with the signed cookie. – Waiting for Dev... Apr 02 '19 at 16:50
  • You can avoid it by storing in the server the expiration time, so you can expire it manually if needed. Of course, then you are very close to the server token scenario, but with a little less burden. – Waiting for Dev... Apr 03 '19 at 04:43

2 Answers2

1

Congratulations! You've just invented the JWT :)

A "remember me" feature isn't practically different than a simple session token, and the entire point of JWTs is to not have store tokens server-side while still validating users.

No need to implement this yourself of course - every language has good libraries for JWTs. You should also read up on their limitations, the biggest of which is the inability to revoke them. That is why they have an expiration, which is usually quite short, and so are combined with a refresh token, which lives longer.

Helpful reference: https://jwt.io

Conor Mancone
  • 29,899
  • 13
  • 91
  • 96
-1

If you're just storing the user name (and not the password), a client-side-only solution is fine. The user will still have to authenticate, so the risk is fairly small, and if the cookie is stolen it isn't very valuable.

If you're storing a token that also authenticates the user, you must also have the server-side token. Otherwise it is impossible to revoke the cookie without revoking everyone else on your system. This make it difficult to support the common situation where the cookie is stolen.

Regardless, I would strongly suggest you test your solution with common password managers, which may not interoperate with your solution correctly. It is very frustrating for an end user to get a user name from one place and the password from another and end up with them out of sync.

John Wu
  • 9,101
  • 1
  • 28
  • 39
  • The cookie only stores a user identifier, but it authenticates if sent to the server, so if the cookie is stolen the risk is very high. But it is the same for every other kind of remember me cookie. As you say, the difference is that with a server token you can revoke access to a single user. You can avoid it by storing in the server the expiration time, so you can expire it manually if needed. Of course, then you are very close to the server token scenario, but with a little less burden. Please, could you clarify the thing about the password manager? I don't see how it relates to it. – Waiting for Dev... Apr 03 '19 at 04:42
  • I thought you were talking about a cookie that helps populate the user name and password fields in your login page. Sounds like you are talking about an access token, literally a session cookie for a persistent session. That absolutely must have a matching token somewhere on the server side. – John Wu Apr 03 '19 at 05:56
  • Why? What kind of attack prevents having a token in the server side that a signed cookie does not, for a persistent session? Forgetting now about the usability issue of not being able to revoke access to a single user in the system (because it's not a security concern, as I can revoke all users, which, for example, isn't neither a terrible usability issue for an admin backend with three or four users) – Waiting for Dev... Apr 03 '19 at 07:55
  • You asked a question: do we need a server side token if the cookie is signed by the server? Answer is yes and for very exact reason you are excluding. It is a security concern since the token is access token or refresh token. These can be stolen. From security perspective, you need to have a way of disabling user access on backend. You said it is an admin backend with three or four users. Is it an internal company application? What if the user leaves the company? – Marko Vodopija Apr 03 '19 at 08:54
  • Then I can revoke access to all the users changing the server secret . They just need to sign in again. It is an annoyance (but they have to sign in again from time to time when its remember me cookie expires, anyway), but not a risk. So it is a usability issue, not a security issue. I'm not trying to talk about generic good practices here, but just to focus on security in order to understand possibilities. Because, again, a middle way solution is to save the expiration time in the database and sign in the cookie. This way I don't need a hashed token and I can still revoke a single user. – Waiting for Dev... Apr 03 '19 at 10:10