7 ms·
JWT were aiming to be stateless, yet they cannot be stateless if you need them to be revocable. If you keep using plain sessions you got a SPOF, but you are imm
by altmind 7y ago
JWT were aiming to be stateless, yet they cannot be stateless if you need them to be revocable. If you keep using plain sessions you got a SPOF, but you are immune, for a whole lot of consistency and cred management problems.
http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-for-sessions-part-2-why-your-solution-doesnt-work/ http://cryto.net/~joepie91/blog/2016/06/19/stop-using-jwt-fo...
- deleted 7y ago[deleted]
- JMTQp8lwXL 7y agoYou can revoke all JWTs by changing the signing key on your server. All previously issued JWTs will be invalid.
- ceejayoz 7y agoSure, but that's the nuclear option. Imagine if Facebook did that every time one account was compromised or they fired a staffer?
- JMTQp8lwXL 7y agoFacebook as the largest userbase of any application in existence. Its needs may not equate to your needs. For example, an enterprise b2b app with a few hundred customers could probably "deal with" the nuclear option.
- ceejayoz 7y agoI'd be pretty upset if I got kicked out of a work app every time one of a few hundred companies fired someone (or even had to do a password reset for a security reason).
- JMTQp8lwXL 7y agoYou don't use a tool for managing your passwords? That's built into most browsers these days.
- ceejayoz 7y agoThe issue is not remembering the password. The issue is I just logged in 90 seconds ago, typed up a few paragraphs, and when I go to submit I have to do it again, because someone in another company using the tool got phished and needs a new password. It's frustrating enough when Gmail makes me put my password in after 30 days and I just clicked into an email I wanted to read. Having it happen all day long would make me want to kill someone.
- JMTQp8lwXL 7y agoI wasn't suggesting mutating the signing key multiple times per day or once per 90 seconds. At that point, you might as well just have a very early JWT expiration timestamp specified.
- ceejayoz 7y agoThe comment thread started with "if you need them to be revocable". Any tool with "a few hundred [enterprise] customers" needs to be able to revoke access for terminated employees, compromised accounts, and the like, and those revocations will occur frequently and in many cases need to have immediate impact.
- bingotips 7y agoA multi-tenant system could use a different key-pair for each tenant and only revoke the one for the compromised entity
- TheFiend7 7y agoMan I'm not sure I agree with that. Blowing up a bunch of your clients that rely on your services randomly because one account was compromised is not acceptable for really any professional business regardless of the number of clients.
- JMTQp8lwXL 7y ago"Blowing them up" is a mischaracterization of the situation. You are not mutating their data. You're only asking them to login again.
- SkyPuncher 7y agoActually blowing them up is a completely appropriate description if you have any non-human's relying on JWTs.
- onion2k 7y agoApplications that use authenticated services need to handle being the authentication being revoked. That's fairly obvious regardless of how it happens. If your app doesn't then it's broken.
- rvz 7y agoSo now every user has to log back in again every time you upgrade your server, simply changing the signing key or when your backend gets compromised. Additionally JWEs don't support forward-secrecy meaning that I can MITM and collect all JWEs passing through, find the key in your compromised backend and decrypt ALL these collected tokens. No need to do this with JWTs since they're unencrypted by default.
- JMTQp8lwXL 7y agoYour server shouldn't be getting compromised on a regular basis. The occasional black swan event occurs, and sometimes you have no other choice.
- staticassertion 7y agoUsers get compromised though and will want to revoke sessions. But this is why you just set a time limit on your JWT, so that they can revoke and within N minutes the old sessions will die. Just keep N low.
- wcip 7y ago>Just keep N low. "Your self driving car has been compromised, but don't worry sir the attackers will relinquish control at some point in the next 30 seconds" In my view JWT are fine so long as you don't really care about whatever is they are being used for.
- deleted 7y ago[deleted]
- jchw 7y agoTo be clear though you generally set the validity to be relatively short and refresh often, so that way you don’t have to worry too much; you can then “revoke” a token by refusing to refresh it.
- jayd16 7y agoThe link seems to think this is impossible but I don't understand why.
- jchw 7y agoDon’t see the word “refresh” in there. Guessing they are assuming you use JWT identically to how you might use a session cookie, which is not how I’ve ever seen it used, personally.
- jayd16 7y agoIn the diagram in the bottom right they seem to think you cannot revoke the long term token. I agree that it doesn't align with my understanding of whats capable with oauth2 style tokens, for example.
- cstrahan 7y agoThat box should probably read: “You can't revoke the long-term tokens in a stateless manner, so supposing you truly manage ZERO state, then you're back to square one.” That seems like the charitable interpretation. Note that the author’s point has not been that JWT is useless, but rather that trying to use stateless JWT for sessions is a bad idea. If the point of using for JWT was to avoid all server side state in authn/authz flow — which is the case for many, many developers, and that is the intended audience of the author’s post — then one of two things: you either contradict yourself and implement server side revocation for refresh tokens, or you let the lifetime of your sessions be the same as the refresh token — and in the case of refresh tokens with no expiry, the user (or anyone with their refresh token) can stay logged in forever.
- 7y ago
- jayd16 7y agoSo wait, why does the refresh token not work? Why wouldn't you verify user permissions when generating a new access token?
- msbarnett 7y agoYou need a really short refresh cycle for that to be useful to customers. If your customer FooCorp fired Bob, they want to be able to disable his access immediately, not in 3 days when his access token next needs a refresh.
- deleted 7y ago[deleted]
- jayd16 7y ago15 minutes seems to satisfy most use cases.
- cstrahan 7y agoRemember that the author’s intended audience is developers who want to use JWTs specifically to avoid server side state in the authentication/authorization logic. The point is that, if you want to revoke the refresh token, you have to maintain a blacklist somewhere, and now you’ve contradicted your original goal of avoiding all state, which means that choosing JWT for this particular purpose was illogical, and probably warrants further thought. (TBC, in logic, if your hypothesis leads to a contradiction, then your hypothesis must be false, which is exactly what we’re seeing here in this scenario.)
- 0x5345414e 7y ago> revoke the refresh token, you have to maintain a blacklist somewhere Store CreationDate in the refresh token. Store RefreshTokenInvalidBefore in the user record. When refresh is attempted, if Token.CreationDate <= User.RefreshTokenInvalidBefore, reject the refresh. The only drawback here is that it would sign the user out on all devices. However, assuming this is because of a password or token compromise, that's likely the least of their worries.
- nicoburns 7y agoIt's not stateless, it just uses a blacklist instead of a whitelist.
- stephenr 7y ago> If you keep using plain sessions you got a SPOF What single point of failure is inherent with plain server side sessions and a session cookie?
- ratherbefuddled 7y agoThe server.
- stephenr 7y ago... ok so assuming you then don’t have a HA environment (Really!?) if the server is down the sessions and the tokens are irrelevant because there’s nothing being served and nothing to use/check them and provide back resources.
- james_s_tayler 7y agoYou don't have to store them purely in-process. The session data itself can live in Redis. You can scale sessions beyond a single web server.
- m-i-l 7y agoFor more secure apps we use single use tokens and expire within a very short period of issuance, i.e. invalidated upon use, and exp (expiry) set a few seconds after iat (issued at). Not optimum for performance because you need to get a new token with every request, but means you never have to worry about having to revoke them. Not heard of anyone in the finance sector using JWT for session management, but that's not what they're for.
- whateveracct 7y agoRevoking per-JWT requires state per-JWT, but you can get away with globally-revokable tokens ('logout everywhere' functionality) with a single nonce-per-entity instead of a nonce-per-JWT, which is a bit nicer.
- 0xkalle 7y agoRight. One point to keep an eye on is, if you are using (e.g.) AWS API Gateway with a custom authorizer, it caches the authentication response for a certain time. This is not a problem of jwt, but makes the 'logout everywhere' and every black and whitelist need some more time.
- notyourday 7y agoOf course you can. Put your auth behind a sane CDN with TTL of forever, the kind that allows tagging an arbitrary number of objects with a single tag and allow to purge objects matching a tag in a single call within a few milliseconds. Tag them with sec-uid, sec-uid-dev-id, sec-devclass, sec-we-dont-like-user etc to group them together. Want to kill sessions of just user uid? Hit a purge endpoint that purges all objects with sec-uid. Want to kill a session for a specific user for a specific device? Hit the purge endpoint that purges all objects with a tag sec-uid-sec-devid. Want to logout all users on an iPhone because "oops, security bug in a version we rolled out"? Hit an endpoint that purges all the docs tagged with sec-devclass of an iphone. You don't even need to remember tokens you issued.
- jakelazaroff 7y agoYou are describing stateful authentication.
- notyourday 7y agoNope. You don't even need to know you issued those tokens or their state. You don't ever assert a state or check it. You force its recompute via cache bust. You don't need to know a token of jakelazaroff. You don't need to know its state. You don't even need to know if it exists. You know that a token associated with jakelazaroff iphone if it exists will have a tag jakelazaroff-iphone because every token associated with <user> iphone will always have a tag <user>-iphone since you always tag a token of any <user> on an iphone with a tag <username>-iphone when you issue the token.
- deleted 7y ago[deleted]
- jakelazaroff 7y agoI don’t understand your explanation, but the words that you’re using (e.g. “purges”, “cache”) indicate that you’re describing a stateful system. Imagine you’re writing your API on AWS Lambda, so memory and the file system are not shared between requests. A client presents your API with a token. Using no external resources (no database hits, no network requests, etc) how do you determine the veracity of that token? Edit: I think I understand what you’re saying. Using a CDN that will let you “tag” resources and conditionally provide access based on whether HTTP headers match those tags, you issue tokens to clients and add or remove tags to give and revoke access. The CDN determines whether a given tag can access the resource, and your application doesn’t worry about authentication. This is still stateful. The tags are the state!
- mgraczyk 7y agoThe state necessary to revoke JWTs is easier to manage than session state. 1. It's small (id per revoked, nonexpired JWT) 2. It isn't sensitive, nobody learns anything by seeing the list of revoked JWT ids. 3. It's monotonic. You just maintain a set that you add to. You can clean up expired tokens if you want but that's not necessary for correctness. These three items make bugs less likely and make it easier to manage consistency when you can't afford to use transactions everywhere.
- namibj 7y agoThe monotonicity alone makes the required state _very_ easy. Adding (timestamp, jwt_id) pairs to a monotonic set which you occasionally switch over to a second, fresh set (checking against both, adding to one) requires zero coordination in the critical path. The only coordination required is about when the sets are switched, where you need to ensure that you leave ample time for old JWTs to expire before clearing the corresponding revocation set entries.
- mikeymz 7y agoRather than blacklist JTIs would it not be simpler to keep a valid after date on the user? Any token issued before that date is not acceptable
- mgraczyk 7y agoThen you can't have users sign out of device A while remaining signed into device B.
- pierreocinom 7y agoAn approach I have used in the past is including the optional `kid` header. The key id can be matched to the appropriate key needed to verify the signature. If you associate every user with a key, that means you can also delete any key and thus revoke the jwt of a particular user. In this case obviously you have a persistence layer for the keys and can't claim to be absolutely stateless. https://tools.ietf.org/html/rfc7515#section-4.1.4 https://tools.ietf.org/html/rfc7515#section-4.1.4