12 ms·
Top reason for me always was : > You cannot invalidate individual JWT tokens And there are more security problems. Unlike sessions - which can be invalidated b
by drinchev 8y ago
Top reason for me always was :
> You cannot invalidate individual JWT tokens
And there are more security problems. Unlike sessions - which can be invalidated by the server whenever it feels like it - individual stateless JWT tokens cannot be invalidated. By design, they will be valid until they expire, no matter what happens. This means that you cannot, for example, invalidate the session of an attacker after detecting a compromise. You also cannot invalidate old sessions when a user changes their password.
> You are essentially powerless, and cannot 'kill' a session without building complex (and stateful!) infrastructure to explicitly detect and reject them, defeating the entire point of using stateless JWT tokens to begin with.
- tehlike 8y agoNot true. Encode a token and validate it against a constant, which you change in case of a compromise.
- anonymousJim12 8y agoHow do you encode it in such a way that you can invalidate individual tokens? How do you distribute that information among your services?
- dperfect 8y agoIn the past, I've compared the "iat" (issued at) value with a column in the users table called "invalidate_tokens_before". If I need to invalidate tokens for a user (for my use case, it would always be all tokens for a user at once), I just touch that timestamp column. True, it still required a db lookup (one that happens anyway), but I found that easier to manage than storing and managing session tokens.
- ivanhoe 8y agoAnd how is that better than using sessions in the first place? What is your gain?
- the_af 8y agoDoesn't the author cover this in their rebuttal (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...), "Your blacklisting/revocation server goes down, now what?". Everything from there goes to "Congratulations! You've just re-invented sessions (only with a less battle-tested implementation) and gained nothing in the process" (Sarcasm is from the author's post, not mine!)
- dperfect 8y agoI don’t think of JWT as a replacement for db lookups or storage, but they do provide a convenience in not having to store and manage all sessions in the database[1]. I’ve done it both ways, and as long as you’re careful about a few of the potential security issues with JWT (solve it once, put it in a reusable module), it actually does save a considerable amount of code and complexity on the server side. Also, in my case, "your blacklisting/revocation server goes down" means the whole application is down anyway, so that's kind of a moot point. You may disagree, and there are valid reasons to avoid JWT. I'm just saying that under the right circumstances, it can be useful. [1] The author claims that JWT isn't any easier, but then later says things like "Expiration can be implemented server-side just as well, and many implementations do". That's true, but it is something extra you have to implement yourself, i.e., not easier (for that feature at least).
- SiempreViernes 8y agoThe author is pretty clearly comparing using jwts with using some framework provided session solution, not having you implement sessions from scratch. So just use a session library with expiration implemented, don’t take one without and add it on yourself.
- the_af 8y agoExactly! Because if you're implementing everything from scratch, you'd have to check the JWT's expiration yourself... it won't automatically expire by itself otherwise.
- joshstrange 8y agoThe way we do it is with a long lived JWT (LLJWT) and short lived jwt (SLJWT). Our LLJWT lasts for a long time (think years) and is only able to to request a SLJWT, it alone has no abilities. Inside the LLJWT we store a UUID that we also store in the DB. The SLJWT is only valid for 1hr (we are testing on bringing that down to like 10min or so) and when it expires you have to use the LLJWT to request a new SLJWT. If at anytime we determine that there is abuse going on or someone wants to "remotely sign out" of a device they can invalidate the LLJWT and the next time it is used to request a new SLJWT it will be rejected.
- icebraining 8y agoIf you need to access the DB to check if you can emit a new SLJWT, what's the point of the LLJWT? Why not just store that UUID by itself? The SLJWT does seem useful, but 1h seems too much; if I fear someone might be (for example) accessing my email account using a stolen or hijacked device, they can do plenty of damage in that time. Do you make it clear to the user that their request for a remote sign out might take that long to be applied?
- joshstrange 8y ago> If you need to access the DB to check if you can emit a new SLJWT, what's the point of the LLJWT? It doesn't have to hit the DB, it could hit memcache or similar caching layer. It also means we could separate this table out from our main DB. We have done neither because it hasn't been an issue (performance-wise) yet. > Why not just store that UUID by itself? We could do that, our thought process was that we wanted everything to be a JWT and we liked the ability to, given a JWT, know who it was issued to, when it was issues, and when it expires, all without going to the DB. > The SLJWT does seem useful, but 1h seems too much; if I fear someone might be (for example) accessing my email account using a stolen or hijacked device, they can do plenty of damage in that time. Do you make it clear to the user that their request for a remote sign out might take that long to be applied? Totally agree on 1hr being too long and that is why we are planning on lowering it. We have technical reasons (legacy apps that we are trying to get updated) that will not work with lower than 1 hour (I won't bore people here with the details and there are workarounds but we haven't implemented them yet)
- lvh 8y agoSo you're saying you can have sane sessions as long as you have some server-side storage? :-)
- tehlike 8y agoYes, of course, jwt can facilitate that. Using it as a replacement is not good, i agree.
- jrochkind1 8y agoBut what value is it adding over ordinary 'bearer token' sessions in that case?
- Spivak 8y agoWhen you aren't invalidating tokens your app server can serve all static but restricted content without checking with the DB.
- deleted 8y ago[deleted]
- zhobbs 8y agoWith this method isn't the downside that you have to invalidate all tokens, and not just the attacker's tokens?
- gammateam 8y agowhich isn't bad because all the processing is done client side anyway.
- merlincorey 8y ago> which isn't bad because all the processing is done client side anyway. I believe people are downvoting you because you may have overlooked the processing that must happen on the server to encode the token in the first place.
- mschuster91 8y agoOr, implement a "master token" scheme: have a long-lived master token, which is used only for generating short-lived (e.g. 5 min) tokens that are actually used for authentication/authorization at the API endpoint. User gets banned or privileges revoked? Fine, revoke the master token on the authentication server and after 5 minutes at the latest, the user is locked out as he cannot get new valid short-lived tokens. Sessions aren't difficult - as long as you stick to one language and environment (e.g. PHP). But as soon as you throw in for example Java to communicate with a SAP backend (as an online-shop system might need to), nodejs for a "support/sales chat" system and whatever, a JWT scheme is easier to implement.
- nine_k 8y ago> Fine, revoke the master token This is exactly the ability which JWT lacks. You can, of course, combine a session ID (checked against a DB) with a short-lived token (stateless, with expiration time encoded). This will allow to only check the session against a DB if, say, more than 30 seconds has passed since the previous check. It helps with spiky traffic, and still allows to invalidate a session soon enough for practical reasons.
- vegardx 8y agoAnd this reduces complexity of all backend systems, as they only have to deal with one mechanism for authentication and authorization.
- martin-adams 8y ago>> Fine, revoke the master token on the authentication server and after 5 minutes at the latest That might be fine for a lot of use cases. But anything that can steal money using that token and 5 minutes is a very long time indeed.
- mschuster91 8y agoBut anything that can steal money using that token and 5 minutes is a very long time indeed. Then implement a check for the token in destructive operations. Should keep the performance impact pretty low.
- the_af 8y agoDoesn't the author address this in their "Why your solution doesn't work" flowchart? Everything ends up a reinvention of traditional sessions, only with a less battle-tested implementation.
- drinchev 8y agoWhat's the point of having a token if you need to check it with a database on every request? Instead of `SELECT isValid from tokens where token="<TOKEN>"`, why not `SELECT user from sessions where session="<COOKIE-SESSION>"`?
- enraged_camel 8y agoExactly, the moment you add statefulness you've basically reinvented session authentication.
- Alex3917 8y agoThere are a lot of problems with storing cookies when the front end and back end are hosted on different domains though. That is the main reason why people use JWTs with SPA apps, because otherwise it wouldn't really be possible to serve the front end from a CDN. Most people using JWTs aren't using them because they're stateless, but rather because it's the only way to solve the problem.
- joking 8y agoWith jwt you have a standarized way to get the data on the client side for example.
- davidwparker 8y agoWhy are checking against the DB here? Parent said a constant. You'd just check the constant value within the JWT vs the constant on the backend, and update the backend constant to invalidate.
- the_af 8y ago(Correct me if I misunderstand you) If you check against a single constant in the backend, are you invalidating all JWTs for all users whenever you want to invalidate only one? Even if you keep a blacklist of invalidated JWTs, how do you keep it up to date? How do you distribute it? What happens if the blacklist becomes unavailable for whatever reasons?
- 8y ago
- EpicEng 8y agoIn which case you wouldn't use JWT tokens at all...
- caiob 8y agoWhy not just "invalidate" the client? At best, you're making your application "safe" for 900ms or whatever the expiry date is.
- detaro 8y agoWhat do you mean by "invalidate the client"?
- caiob 8y agoSeriously?
- dpark 8y agoI would like to know what you mean. “Invalidating the client” seems almost nonsensical since you don’t control the client.
- caiob 8y agoYou do control what clients (think client_id/secret) can use your APIs. Don't you? You figure it out from there.
- dpark 8y agoNo. The discussion here is about using JWT for sessions with web clients. If you’re registering a dedicated client id and secret for each web client, they you’re doing something wrong. If you’re doing this and then also using JWT, then you’re doing something really bizarre, and still wrong. Id/secret pairs can make lots of sense for integrating partner services with your API. They make no sense for web clients, where you should be authing a user and not a client.
- caiob 8y agoClassic hostility on HN. I'm out, I'll go find my tribe.
- vegardx 8y agoThe reality is that hardly anything needs to be instant. You're powerless in the time period that you're setting. You don't need to have Reddit-scale traffic to have to consider this, but when you deal with a lot of backend systems it can reduce complexity a lot.
- tptacek 8y agoIsn't this like the one component of an application design where you really do need it to be instant? People get confused because invalidation doesn't happen often. But you also don't use a fire extinguisher often, and you get those checked all the time to... wait, bad example.
- vegardx 8y agoI guess that depends on the application. So long as you can guarantee that it happens within a given time frame that might very well be good enough. That said, I don't think a lot of people really take this into consideration when they use a stateless JWTs, or the computation required to issue really short lived tokens. Aaaand now I have to check my fire extinguisher.
- zerkten 8y ago> I guess that depends on the application. So long as you can guarantee that it happens within a given time frame that might very well be good enough. I think the right answer is that you need to develop some type of threat models, review them periodically, and then decide what's right. Just because you can't think of a problem with the approach now doesn't mean it won't happen later, or be a component of a larger attack. The "given time frame" above may be more than enough for certain attacks you can identify in initial threat modeling. From the long-term operational perspective, it may also be preferable for the application owner to have immediate invalidation. This might be inconvenient to the development team just trying to get their work done now, but is it a good idea to ignore this requirement? For various reasons, dev teams tend to push on only for there to be problems later.
- abledon 8y agoHow the heck did JWT get such a following with issues like these?
- intothemild 8y agoBecause front-end engineers always fall for whatever cult is hyped right now. They usually don’t understand the issues around the things they want to build, they do it because it’s cool and new, and don’t stop to ask or research anything.
- ponyous 8y agoAnd backend engineers not researching how to properly implement them and completely missing the point, yet arguing and blaming front end devs for being "useless". /sarcasm On a serious note: JWTs have use cases, but your company is probably not the one. Nice thing about JWT is that there is no need to query the DB every time a request hits a service. JWTs for session should be short lived and refreshed often. In case you need to invalidate it, you invalidate refresh token and window for attack becomes short. It's not perfect but it's certainly not useless and just the hype.
- deleted 8y ago[deleted]
- rusk 8y agoHaving recently joined a project that uses JWT (I was completely ignorant of it beforehand - cookies all the way), I can say that a key advantage is convenience for developers and testing. Once you have the secret for signing you can pretty much access any of the application without having to jimmy the access-controls. I guess that could be a weakness too, but in my experience in fast moving commercially driven environments with little technical oversight (a lot of the industry these days) developer convenience does seem to drive a lot of design choices ...
- shusson 8y ago> JWT (I was completely ignorant of it beforehand - cookies all the way) JWTs can be stored in cookies. So I don't understand why you say this.
- jehlakj 8y agoInvalidation isn’t hard to do at all. Simply check every half an hour or so. It does slightly undermine the benefit if using jwt tokens, but it’s better than checking against a server for each request. This is why it usually takes some websites 30-60min to completely revoke your password. This may be a concern for highly secure apps, but for most apps I think this will suffice.
- tptacek 8y agoEvery auditor in the world checks to make sure password changes invalidate sessions, and every company with a security team will balk at that finding in a report; it would make your team look like they didn't know what they were doing. No, this isn't a norm.
- jehlakj 8y agoAlthough I agree with the ideal behavior you mentioned, your comment about "every company with a security team" is not true. Google does this with their firebase product using a combination of long and short-lived tokens. I simply offered a reasonable solution to revoke JWT tokens. Would I use them in a project? Probably not. Even so, if an attacker has compromised someone's session, it's probably too late.
- ThePhysicist 8y agoIf you assume that token invalidation happens infrequently it can still be easier to create a communication channel from individual clients/services to the authentication API through which they receive revocation requests/lists than to check every access token explicitly using a combination of API requests and caching (which also introduces invalidation delay). I'd say it really depends on how many requests per second you need to serve, how your architecture looks and how often you have to invalidate tokens. I can definitely see the appeal of JWT tokens for infrastructures with many decentralized services and a very high request load, even when taking into account the added complexity due to invalidation issues.
- manigandham 8y agoYes you can. JWTs are just a standard way to encode state, and can just as easily be sent as a cookie or the Authorization header. How you invalidate either is the same, whether its a database lookup or something else. Article and most of the comments are wholly inaccurate.
- bsamuels 8y agoadding a database lookup is adding state
- manigandham 8y agoThe point is that JWTs are irrelevant to this discussion. How you pass data between client and server can be cookies, or another header. How you encode that data can be JWTs or your own format. It is not either/or. Whether you manage state 100% on client or share it between client and server is an entirely separate topic.
- CiPHPerCoder 8y agoThe whole point of the "JWT for Sessions" design was to prevent server-side storage. Otherwise, they could just use a long random string and maybe HMAC it and call it a day.
- manigandham 8y agoPerhaps, but what they actually are is a standard way to encode some data. Whether that's a single number or entire user session state is up to you. And how you pass that data back and forth is up to you. There are some common usage conventions but the limits described in this article are completely arbitrary.
- CiPHPerCoder 8y agoNobody here was arguing about what JWT is, the article is about how they're often abused in an attempt to obviate server-side persistent data storage in pursuit of "scalability". The title is "Stop using JWT for sessions" not "Stop using JWT". The arguments against JWT themselves are wholly separate: https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-bad-standard-that-everyone-should-avoid https://paragonie.com/blog/2017/03/jwt-json-web-tokens-is-ba...
- xae342 8y agoThis may not be part of the spec per se but you can invalidate them by distributing a bloom filter with revoked tokens and validation times, services just need to poll the service at the granularity needed. This makes scaling still much simpler than one big session store.
- ale_jrb 8y agoThe problem, as the linked 'Slightly Sarcastic Flowchart' says, is: how do you handle the invalidation server going down? If you just assume that tokens are valid in this case, then an attacker just has to kill the server and they're back to being impossible to invalidate. If you assume they're invalid, you're back to having centralised state, which mostly defeats the purpose.
- cbsmith 8y agoThe bloom filter allows you to largely distribute the work of the server, and serves as a reasonable proxy during a failure off the server. More importantly though, there's no reason it need be a centralized server. Invalidated tokens could be broadcast to a wide number of servers that each maintain the invalidated token list (it's a great case for a CRDT, since it is append only with a TTL). Normally it'd be a pretty compact list, and if it isn't, you probably want to take a more defensive posture anyway. ...and beyond that, if an attacker can take out your invalidation server, which needn't be directly accessible to the public, you've already had a pretty serious security breech. I think the least of your problems would be the invalidation server.
- tinus_hn 8y agoIt might even be a real use case for blockchain!
- Ari_Ugwu 8y agoThank you for this. While I love a good old nerd round of 'stump the wizard' I also appreciate someone pumping the breaks with some realism. Some security conversations get to the point where it's stringing together a highly unlikely chain of scenarios requiring multiple pivots, multiple concurrent failures (stochastic or otherwise), and a state sponsored actor in order to slap a 'do not use' recommendation on something. If companies like Nike can run _Magento_ and educational sites still require Flash then I can use JWTs. Maybe...
- kbenson 8y ago> > You are essentially powerless, and cannot 'kill' a session without building complex (and stateful!) infrastructure to explicitly detect and reject them, defeating the entire point of using stateless JWT tokens to begin with. I'mnot sure that's entirely true. It's not hard to include an extra static token within the JWT which is delivered to the servers through an alternative method (pushed with production, or manually set), which when it changes forces a re-auth (either just a DB auth session because you've specifically set the conditions such that you only care if PW changed or some other flag set, or a full login procedure). If the same static token is used for all users, all users will need to do this on the next request. If you subdivide your users by some metric (first x characters of username, some modulo of numeric ID) then you can invalidate some subset of the userbase JWT tokens instead. You've now gained the ability to immediately invalidate a JWT tokens as long as you're okay with forcing extra computation on some larger set of completely valid ones at the same time. Edit: Changed wording of last sentence to clarify you don't necessarily have to invalidate all sessions just by invalidating all JWT tokens, as outlined in further comments below.
- ale_jrb 8y agoThis is true, but kicking off a large subset of the userbase every time an account is compromised (or more realistically, every time someone changes their password—which should certainly invalidate their old tokens) isn't going to be a valid trade off for most applications with customers.
- kbenson 8y agoYou don't have to kick them off. You can make it a trigger to just check whether their session has been invalidated. Store last password change date or something similar, and if the db user is still valid and the password date is older than the JWT creation date, just update the JWT and let them continue. If not, require a new login procedure or deny outright, depending on account status. > every time someone changes their password—which should certainly invalidate their old tokens Using a variation of above, you can just reverify the JWT every X minutes, and know that if you change a password for normal reasons all JWT tokens will be invalidated within X minutes. It's a trade off. If you can live with what you're trading (or at least live with it after mitigations are put in place), it might be worth it.
- Alex3917 8y ago> This means that you cannot, for example, invalidate the session of an attacker after detecting a compromise. You also cannot invalidate old sessions when a user changes their password. Sure you can. Just have a 'date_password_last_changed' field on your user model, and compare that with the issued_at date on the jwt. Since your user model presumably gets retrieved for each authenticated request anyway, there are zero extra database lookups. Similarly, if there is a global compromise then just rotate the secret key use used to signed the JWT.
- m4n 8y agoUpdating the 'date_password_last_changed' will invalidate all the tokens for a user. It solves the purpose but has its own trade offs.
- Alex3917 8y ago> Updating the 'date_password_last_changed' will invalidate all the tokens for a user. If someone is changing their password because it has potentially been compromised, what is a scenario where you would not want to invalidate all of their existing tokens?
- GhostVII 8y agoCouldn't you use JWT's with both an access token and a refresh token? The access token can have a fairly short expiry time, after which you hit the auth service with the refresh token, at which point you can handle any token invalidation, while still allowing most of your requests to go through just using the JWT.
- matthewaveryusa 8y agoShort TTLs on tokens can work very well depending on what the goal is. If you're doing high-ops and your goal is to reduce authorization calls the TTL acts effectively as a cache that decouples API ops and authorization ops. The compromise being that you can only rotate as fast as the TTL. That is of course unless you want to implement revocation-list capabilities. But if your revocation-list server goes down you're back to the TTL limitation.