9

I'm writing an app-server and there is an option to just use secure cookies for authentication. Here's how it seems to work:

  1. You define a 32-byte secret key on the server
  2. When the user logs in, you check the database to see if the bcrypt hashes match, and if so, you call request.remember(user_id)
  3. On route handlers that require authentication (and the user_id), you unwrap the user_id by decrypting the cookie and if it's valid, you continue. Otherwise, return an Unauthorized error.
  4. If a user hits the logout handler I just call request.forget() and the cookie is deleted on the client.

This all seems to work. So what I'm curious about is why doesn't everyone just do this? I look around and there seems to be a lot of talk of JWTs, generating auth token UUIDs and storing them in Redis/the database, etc. So apparently this method isn't secure? And you need to store state on the server?

If I were to guess, I'd say a problem with this approach might be that if the cookie is stolen somehow (not sure how since it's all over TLS and the cookies are HTTP-Only and Secure if that matters), then the user would be able to be impersonated by an attacker. But I think this would apply to the other schemes too?

Another issue I could see is that a user could just randomly generate auth tokens until they found one that matched a user? But I'm not sure if this is a problem either since I'd just rate limit the authentication handler and I'd imagine this sort of thing would take a while? Oh, maybe they could make 100 accounts and see what the encrypted cookie auth token looked like and bruteforce it client-side to find out what the secret key on the server was? And then they'd be able to impersonate users by generating auth tokens? Although I think it would take way too long to find the key since it's 32 bytes?

I guess this approach doesn't automatically expire cookies (is that why this isn't used much? But I think there's a way to add an expiry header to cookies? Would that work?) I'm not even sure if I need expiration for this app.. Seems like it would annoy users. How long do sessions last at places like Google/Facebook? I feel like I'm always logged into those services forever.

I don't know. I feel like I'm missing a lot of information here. Is there somewhere where I can find a pros and cons list of all these different approaches?

  • 1
    There are some users who never allow cookies. Do you want to force them to? – rookie099 Oct 16 '18 at 5:11
  • 1
    What does request.remember and request.forget do here? And what do you use the 32 byte secret key for? You mention decrypting a cookie, but not encrypting or setting any cookies. – Anders Oct 16 '18 at 7:16
  • 1
    @rookie099 If you never allow cookies and no other client side information storage? No session storage? – curiousguy Oct 16 '18 at 8:09
  • 1
    Don’t let yourself become confused about some sane approach just because some other people are using or trying to use some more fashionable technologies or the shiny new thing of the week. – caw Oct 17 '18 at 13:44
  • @curiousguy You can still preserve session state for a user who accepts no cookies or other client-side storage by including a session token as a GET variable in every internal URL in every page that you serve to the user. Drawback: their session token will probably end up in your web logs. – Mike Scott Oct 21 '18 at 13:11
4

The scheme you describe is potentially vulnerable to cross site request forgery (CSRF).

An malicious request could be made on behalf of the user. This request would send the cookie which would pass the authentication checks, and perform any activity the user could themselves.

https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)

If you look at the link above to the OWASP article on CSRF it specifically lists secret cookies as an invalid mitigation technique.

  • 1
    Okay, I'm going to read up on this. Is this the only vulnerability? Also, is there any way to mitigate this vulnerability while still using stateless cookies? It looks like I might be able to use an HMAC – Chron Bag Oct 15 '18 at 23:02
  • Normally you would create a token when the user loaded a page where they had the potential to make a change, and that token would be appended to the URL (if it was a link) or added as a field if it's a POST. I don't see how a HMAC would solve your problem. To address your other point, it's impossible to say a scheme is secure unless you review the source, because the implementation is usually not perfect (bugs). If you can, I suggest using authentication scheme's made available by the framework you're using or a third party like OAutuh. No reason to remake the wheel. – Daisetsu Oct 15 '18 at 23:10
  • 3
    owasp.org/index.php/… ? – Chron Bag Oct 15 '18 at 23:18
  • 1
    Ah, you mean using HMAC to generate the token? Yeah, that would work. I thought you meant using the HMAC in the cookie. – Daisetsu Oct 15 '18 at 23:20
  • So it's fine? Why does everyone use stuff like state and json web tokens then? – Chron Bag Oct 15 '18 at 23:22
3

Assuming you are using your cookies as a stateless authentication identifier then your scheme is basically similar to JWT except created with cookies. The main differences are:

  1. JWTs are generally only signed instead of encrypted (though you can encrypt them as well). What this means is that you can ask third party services to create tokens for you. This allows you to plug your application into other authentication services or provide an authentication service yourself for other apps.
  2. Mobile native apps and cookies might create problems. Generally can be overcome but the implementation can be a lot trickier than using tokens which only need to be attached as text to a request header or body and are easily stored.
  3. JWTs are easier to work with especially in javascript environments as you can pretty much attach any metadata you want to the claims and can read them as you would normal JSON. It also helps that with their popularity you can find ready-built solutions for more of the modern frameworks.
  4. Cookies are vulnerable to cross-site request forgery (CSRF) while tokens will depend on how you store them (cross-site scripting (XSS) if in web storage, CSRF if you decide on storage cookie).

In summary what you are suggesting is solid, but it's basically the same as JWT missing a few of the benefits. If your system has no need for third party integration then by all means go with cookies, but make sure to secure them against CSRF as mentioned by @Daisetsu.

0

You're mostly right. The cookie is encrypted, so the contents cannot be seen or messed with. (Unless the encryption is broken.) The cookie is sent only over TLS, so it can't be stolen by a MITM. (Unless your cert is compromised somehow.) The cookie is set to HTTP-Only, so it can't be stolen by any malicious JS. From all of the angles that make sense, it's safe.

I have but one gripe with your setup. You're using a persistent identifier for the user in that cookie. In the unlikely event that something does go wrong, the compromise will last the lifetime of your user record. Generate some random string, store that someplace, and use it to reference your user. That way, you're constantly recycling what would ID a user, containing any breach to the session lifetime.

Consider also opening up popular frameworks and studying how they handle this. You may pick up some useful techniques to make things even safer or more efficient.

As for JWTs and such, there's a blend of them being the new shiny that people want to use and them being a genuinely useful technique for having authentication exist on a separate system than where the user needs to be authenticated.

Edit: Did a little diving into Laravel to see how they do it. They just store the user ID into session. Session is server-side and therefore safe. This separates it from session handling, which seems proper. The session identifier is a random 40 character string. That gets set as HTTP-Only.

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.