11 ms·
JWTs are good for API tokens, not end users. If you use JWTs for your cookies/session state, then you'll still need to maintain a table of valid JWTs and expire
by rsj_hn 5y ago
JWTs are good for API tokens, not end users. If you use JWTs for your cookies/session state, then you'll still need to maintain a table of valid JWTs and expire them when the user logs out, and thus you will not be able to use JWTs as they were intended to be used, which is as stateless tokens.
Most security auditors/certifications/compliance requirements do not consider even a 5 minute lag acceptable for user driven logout. The definition of logout is that when the user presses the logout button, all the session data is invalidated server-side during roughly the time it takes for a request/response roundtrip.
Thus there is no benefit to using a non-opaque high entropy string for user sessions, even though there is a good benefit to using JWTs as API tokens for back-end services (esp. microservices) that do not have browser logout requirements.
- aflag 5y agoWhy can't you just delete the cookie when the user logs out?
- jakereps 5y agoThat token itself is still valid - regardless of whether or not their browser still has it stored.
- hermanradtke 5y agoThe issue is not deleting the cookie. The issue is that the JWT can still be used as a valid session unless you have some sort of blocklist. Once you introduce a blocklist, you might as well ditch the JWT and use some opaque token stored in a table.
- axiosgunnar 5y agothe entire article could be summed up with this post tbh
- remram 5y agoIs that a problem though? Does your threat model include clients that correctly send logout requests when they're supposed to but don't delete cookies when they're told?
- colinclerk 5y agoYour application should certainly have some resolution to an account being hacked or a session token being stolen. No expiry and no denylist means an attacker can cause problems until you patch your code.
- SigmundA 5y agoNever trust the client, ever.
- remram 5y agoIf that's how you feel, don't trust them to logout when they walk away. Make those sessions short-lived and ask for the password again whenever they do something remotely sensitive.
- jfgiogktkt 5y agoYou logout on a public computer, the next user undeletes the cookie (which is just a row in a profile SQLite database).
- 5y ago
- kokx 5y agoBecause a user could simply provide the cookie again on the next request. If you still see the JWT as valid even though you deleted the cookie, the user could stay logged in during that time. Cookies are managed by the browser, hence they are ultimately controlled by the user.
- spookthesunset 5y agoDepending on the site, that might be fine. For parts of the site that deal with sevitive data… just verify the token with the auth server every request line you would old school. It really depends on the site and how much you care about having a window between logout and all the tokens becoming invalid. Most sites probably have large parts where it is a acceptable to have a few minute interval.
- wglb 5y agoFor a secure site, it is never acceptable to having a non-zero window.
- spookthesunset 5y agoSo all of reddit, every page, needs to reverify its auth token every request? Like, what is the worst that is gonna happen in a five minute window between logout and the token expiring? Sure make the account management pages reverify on every request... maybe even revalidate when you perform a sensitive write action (which is probably far less than 1% of the authenticated traffic). But every read request for a normal user? You are telling me that those all need to re-verify every request? In the case of reddit, by not validating the auth token on every (non-sensitive) read request they could probably shave off 99% of the traffic going to their auth server. Better still it improves page latency as each request doesn't need to block on waiting for a response from the auth server. Faster page loads! And, since you were smart about it... all the stuff where it actually does matter that the token gets verified right away... you can do that too! It's win, win! A lot of people mis-understand JWT or see it implemented incorrectly. JWT is pretty rad, honestly.
- deleted 5y ago[deleted]
- SigmundA 5y agoNever trust the client
- jrockway 5y agoBecause the session material could be compromised. How do you revoke tokens on lost laptops? What if you accidentally checked the token into Github and realized your mistake? What if malware captured the token? You have to be able to revoke access on the server side. You can use JWTs and have a "revoked_sessions" table that works like a normal "sessions" table. At the start of the request, check if the token is in the "revoked_sessions" table and deny access if it is. But there simply isn't a point; this has the same performance and latency considerations that a normal sessions table has ... but with many more possible ways to screw it up. "Sessions with extra steps."
- e_y_ 5y agoAs the article mentions in a sidenote, a time-bounded revoked sessions table is small enough to keep in memory and can be updated via pubsub for the relatively infrequent case where you need to revoke one. It's definitely more complex but at certain scales it might be worth it.
- rsj_hn 5y agoThe "keep in memory" part is gonna be hard as you scale to multiple servers. You run into all the issues that lead people to stick an oracle DB behind their app servers. I agree that these considerations do pan out in some cases; I'm not saying that any of these proposals can't be the right way to go depending on your overall design, but now we are squarely in optimization-land and have long given up on statelessness.
- Alex3917 5y ago> How do you revoke tokens on lost laptops? Have the user change their password, and store datetime_password_last_changed on the user model. Then just treat any tokens issued before that time as expired. There are some use cases where storing tokens might be necessary, but for most startups this is probably not a good idea.
- jakelazaroff 5y agoThat's exactly the same as checking a list of tokens. If you need to make a DB trip on every request, what advantage are you getting from JWTs?
- wglb 5y agoThe client may decline to delete the cookie. The server can't presume that the client will do the proper thing.
- arkadiyt 5y agoThey're not even good for API tokens. There are valid use cases for storing data in a signed client-side token, but if you're going to do that then don't choose JWT as your serialization format - there have been too many alg:none or other issues. Just do hmac-sha256(data, secret) instead.
- rsj_hn 5y agoyeah, I'm not a fan of JSON or XML signatures, but for some reason developers love them. I've given up on that battle
- lbriner 5y agoWhy would you not like a solid mechanism for verifying that a data packet hasn't been tampered with? In the case of JWTs which live in the browser, it would be essential that they are signed. dotnet auth tokens are also signed, they are stored in cookies, is that any different?
- derefr 5y agoMiddleware like Nginx (at least the Nginx Plus version) know how to take apart JWTs and use the stuff inside. The same can't be said for your arbitrary custom serialization format. The real use of JWTs is when you want third parties to be able to sign their own API requests, that your API will accept using the very same machinery by which it accepts your first-party-client API requests. If you use JWT, you can just pass the third party a private JWT signing key to use, add the corresponding public key to your validation set for JWT decode on your backend, and everything "just works."
- genghisjahn 5y agoOr use rsa for the token signing. 3rd party keeps the private. They send you the public. You can verify all the tokens. They are the only ones that can create new ones.
- derefr 5y ago
- Rapzid 5y ago> maintain a table of valid JWTs and expire them when the user logs out Wouldn't you just need a list of logged-out JWTs? And maintain entries until the JWT would have expired?. And that's if you really cared. Some people would be fine with the client and server participating in the log out and a low-ish JWT expiry.
- rsj_hn 5y ago> Wouldn't you just need a list of logged-out JWTs? Sure, but that's not a real improvement. It's still stateful since you need to check the list with every request, you can't just verify the signature. Changing the logic from "must be in this list" versus "must not be in this list" does not give you much -- maybe some performance gain, depending on the situation. > And that's if you really cared. Well, that's my point. Developers may not care, but from the point of view of a security auditor, it's a vulnerability in your auth system, so the GRC/Security people do care, even if Foo start up doesn't. At some point, if Foo is successful, they will face this issue and need to support real logout to get the certifications they need to do business or be in compliance.
- ecnahc515 5y agoJWTs expire, so you only need to maintain a list of invalidated JWTs that haven't expired yet. You get two short cuts, one that you only check for revoked tokens which aren't expired and have valid signatures. This can save a lot of DB queries given you usually have to check auth validity per request.
- lbriner 5y agoHow does that help? You won't know which tokens should be considered expired in-advance, you still have to call the DB for every request to check. There won't be many that are called with expired tokens compared with people using the site constantly and always having valid tokens.
- bobthebuilders 5y ago
- deleted 5y ago[deleted]
- spookthesunset 5y agoIf your environment is such that 5 minutes of lag between logout end a token being invalidated, you can always just verify the token against the auth server per request. JWT comes in handy for most of your site where it isn’t such a big deal. That way you aren’t flooding your auth server with calls; all your web servers can just validate the token themselves up until a refresh is required. Basically JWT let’s you have your cake and eat it too. Significantly less load on your auth backend while still letting sensitive parts of the site verify on every request.
- ryan-allen 5y agoI don't understand why people are down-voting you.
- spookthesunset 5y agoBecause a lot of people see security in terms of black and white instead of a lot of shades of gray. Not everything requiring authentication is your bank account. HN, for example, could have even a 10 minute window and be okay. Not having to block all your request waiting for the auth backend can improve your latency by a non-trivial amount. It also can make your auth server much less complex. JWT is awesome. People just think it is "all or nothing" and implement it wrong.
- ryan-allen 5y ago> JWT is awesome. That's generally my thought, too. In my career the authentication sophistication was always a trade off (effort vs security) based on how paranoid the org felt about certain things. Having worked on PHP/Rails/.NET Webforms/Node.js apis/C# webapis the session management techniques are all very different. Having run high traffic websites also, the ability to offload logged-in sessions into JWT was really, really nice. Not having to prune auto-generated sessions from disk of PHP applications is a nice thing to not worry about.
- lmm 5y agoI've seen plenty of people make the equal and opposite wasteful mistake: they insist on using a shared state store so that logins can be properly revoked, then they notice that every server looking up the session in this shared store on every request is having a significant performance impact, so instead they have the server cache sessions locally for 5 minutes (or even longer).
- spookthesunset 5y agoThat is the cool thing about JWT. You get the best of both worlds. With JWT you don't have to hit the auth server for requests where a ~5 minute (or whatever) window doesn't matter. That is probably 99% of the authenticated traffic on a lot of sites (thinking of HN, reddit, youtube, etc). On requests that matter, like on a write request or a "sensitive" read request, you can always ping your auth server to make sure the token is still legit. Cutting out 99% of your auth backend traffic can dramatically change how you design it.
- ravenstine 5y agoThis seems like an invented problem. What is an auth server fundamentally? It's a hash table lookup. Which happens to be something that computers are designed to be really good at. I've never worked at a company where auth or storing user sessions was a bottleneck.
- spookthesunset 5y agoI worked at a place whose auth server system literally serviced tens of billions of request per day. 99% of that traffic was for "dude was logged in and is looking at some page that is not unlike the one you are reading right now on HN". JWT let us cut that traffic by 99%. The remaining 1% was for servicing refresh tokens and handling requests for "sensitive" traffic (i.e. account page, anything involving writes, anything dealing with billing). This was in a system with data centers across the globe. Auth might not be your primary bottleneck, but each page load you service has a latency budget and every millisecond spent being blocked on some auth call is a millisecond that could be spent doing else. And trust me, your database or crazy "solve it with redis" server isn't responding in 1ms, it's gonna be at least 20ms due to network overhead and the variance in latency on that request isn't always "20ms" it is "99% of the requests are 20ms and 1% are >>100ms". So now 1% of 10 billion requests (100 million requests) take way longer than 100ms... well that sucks... Not to mention when your auth backend blows up and dies... your site is completely dead in the water. JWT can at least let you tread water for a while. JWT is amazing. People that diss it don't understand it, or likely don't understand the tradeoffs they implicitly made with their own auth architecture.
- adolph 5y agoThe persisted state of user access can be two of consistent, available and partition tolerant. JWT uses cryptography to expand partition tolerance at the expense of consistency. The lower the requirement for consistency latency in user state, the lower partitions are tolerated, such as geographic availability, multi-rack, multi process and so on down to not allowing client-server partition. JWTs are fine when partitions are more important than consistency and a pragmatic choice to avoid centralized state on a backing service.
- whateveracct 5y agoFor users, I like to have a secret key per user and put something signed with this key in a cookie to represent the session. Then "log out everywhere" is as simple as regenerating their secret key. No need to have to persist state for each session, which is nice.
- barrkel 5y agoWhere is the secret key stored? This may not be per session but it is per user, which for most apps is almost the same thing.
- whateveracct 5y agoIt's per-user. Just a column with all their other stuff. Sessions:Users are Many:1 typically so that's not as simple
- tatersolid 5y agoSo you have todo a DB call to get this key on every page load or API request? You’re back to square one. Just use an opaque random session ID
- whateveracct 5y agoI do those anyways - from my user table. But I don't have some extra table of sessions that is append-only (modulo expiration). Cuts out an entire system.
- sly010 5y agoI am confused. Why can't the client just drop the token and be done with it? Why do you need to store session state on the server to be "secure"?
- wglb 5y agoBecause the server thinks that the session is still alive. The server doesn't know that the client has "dropped" the session. If the dropped token should be somehow be found again, it still has all the authority that the original session did.
- hkai 5y agoThis got flagged by our pentest vendor as well, but to me it sounds like a very unrealistic attack vector. If one can steal a token from your browser's storage or can intercept your HTTPS connection, then sure, yes, you have a huge vulnerability even without JWT.
- quickthrower2 5y agoCould make you less secure if the token was leaked somehow (another vuln for example a cross origin type of thing) You notice odd behaviour so you log out to stop it but the attacker isn’t logged out. Also with this setup log out of all devices is not possible! Again something you’d be keen to do if seemingly attacked.
- porker 5y agoI've never got my head round how log out of all devices works. It has to have a central store of all sessions?
- lbriner 5y agoIt depends on what auth you are using. In OpenID Connect, there are back channels that talk to each other so that all devices know you have logged out. If you are using traditional auth then yes, you would need to track session state against the user so that when they access from a particular device, you could check whether they have already logged out. Some more complex apps use a background thread to check auth status with the server.
- speleding 5y agoThere is a much more straightforward way to handle session expiry not mentioned in the article: in most cases your application will need to get something like a "User" object from the database. That object can simply contain a version number that you increase when you need to log someone out. If the version number in the session does not match the one in the JWT you discard it.