The criticisms of JWT seem to fall into two categories:
(1) Criticizing vulnerabilities in particular JWT libraries, as in this article.
(2) Generally criticizing the practice of using any "stateless" client tokens. Because there's no great way to revoke them early while remaining stateless, etc.
The problem is that both of these groups only criticize, neither of them can ever seem to actually recommend any alternatives.
I could care less about JWT per se. I'm happy to implement a similar pattern with something else (e.g. store a secure cookie post-auth, skip all the refresh business and just let it expire when it expires, and employ an ugly revocation strategy only if absolutely necessary). I don't need JWT for this.
If I'm providing a REST API, then I'd prefer a token string that I could pass as a header value rather than forcing the use of cookies. Although I suppose you could argue that a cookie is just another header value.
Either way, if you're serving up a REST API to a JavaScript UI... what's NOT a good option is server-side session state (e.g. Java servlet sessions). That requires you to either: configure your load balancer for sticky-sessions, or employ a solution to share session state across all your server-side instances (which never works very reliably). Moreover, relying on a session isn't a very RESTful auth strategy in the first place.
So if I'm writing a SPA in 2017, then I'm definitely taking a client-side approach and running afoul of the #2 critics. And since JWT is so widely implemented (e.g. if I use a "Login with Google" option then I'm using JWT), I'm probably running afoul of the #1 critics too.
These criticism are fine, I guess. There's no faster route to blog clicks, book sales, speaker invites, and consulting dollars than: (1) telling everyone to jump on this year's hype train, or (2) telling everyone that last year's hype train sucks. What the world really needs is a bit more actual prescriptive recommendations of what to do instead.
I don't see any valid arguments in the post. The issues raised are either mis-implementation or misuse of JWT.
All I am getting is "JWT can be misused in such such way that makes your application vulnerable. And neither its standards nor libraries prevent that, so it sucks".
But when is the last time we see any technology successfully prevented people from being silly?
> But when is the last time we see any technology successfully prevented people from being silly?
You can never stop someone sufficiently motivated to shoot himself in the foot from doing it. But you can make it harder for those who would do it be accident by providing more safety features - in case of security this is usually seen as a good idea (safe defaults etc.)
But this is the biggest thing with any security-sensitive code or practice!
Do not give people options, do not allow algorithmic flexibility, do not have fallbacks, do not have backward compatibility, do not allow "testing" or "insecure" options, do not have complex state machine behavior.
All of these things are exactly what JWT or other "design by commission" standards like SSL suffer from and they have predictably lead to ongoing, at times unfixable security problems.
I use stateful JWTs for session management, storing them in localStorage. If someone can exfiltrate the token, they will get a week long authorization, as well as some identifiable information (username, name and role).
Probably I can achieve the same overall system with cryptographically secure session cookies, that are persisted in a database, or other store that is accessible across multiple servers. I guess it would amount to the same thing.
Originally I implemented it because:
* My systems are SPA's. Totally JS dependent from the word go.
* I felt like there would be some advantages to being able to establish certain claims without verification. Say for display purposes prior to server comms (show a list of multiple available sessions for example)...In practise this hasn't really been true. Generally I find in the end I am always checking and verifying anyway - without any huge overhead.
* I've always had a sort of fuzz of uncertainty about Cookies. They always felt a bit out of my hands. Thinking it about rigorously of course, people can switch off JS. They can switch off persistence.
* All my user's local data can be persisted in one place, rather than having to store a reference in the Cookie and then lookup in localStorage. In reality though the code for this is pretty trivial...
So overall while I don't know how right he is, I feel like maybe he has a point. Why not just use cookies?
Maybe it's just because as a JS dev, I want everything to stay within a JS universe...and for some reason Cookies have always felt outside of that to me.
If I can offer some advice in the other direction, don't use cookies.
I tried to do the right thing, use HTTP-only cookies set over an HTTPS endpoint only to find that it's stupidly complicated and has a lot of annoying edge cases. Turns out iOS's webviews don't like them, iOS in general doesn't like them to be on api.hostname.com if the app is on app.hostname.com, you can't validate if you are logged in or not without doing a web request (which is annoying as hell if you are trying to keep a "logged in" state in something like a react app), you need to deal with a bunch of stupid flags to get the damn browser to even let them go across domains, and a hell of a lot of other annoyances that I can't remember right now.
We are most likely moving to something like JWTs (stored in localstorage or indexeddb) soon because of these issues.
> So overall while I don't know how right he is, I feel like maybe he has a point. Why not just use cookies?
Because in a highly distributed system hitting a database to validate authorization is expensive and causes bottlenecks.
A cookie that requires you to hit the database does not solve that issue. Although if the cookie was signed some way that can be cryptographically verified then great. But then you are essentially re-implementing something you could be doing in a standard way instead.
A lot of people are talking about the "none" algorithm issue, but the more recent vulnerability[0] is more telling: The report to the working group mailing list[1] led to the point that the standard had a "security considerations" section in the RFC, and this particular issue was never covered.
And now there are difficulties around the fact they cannot update an RFC which people will refer to for years.
It's not a vulnerability in one or two libraries - it looks like just about every made the same mistake, which points to something much more broken.
As long as the problem is known to the developers and the key is specified, I think the biggest issue of JWT is the lack of session invalidation (that is, if you log out your already emitted tokens are still valid until their expiration), but it's a good tradeoff for not having server sessions.
Session invalidation is possible though, by maintaining a (short) blacklist of tokens on the server. JSON Web Tokens can be given an ID (via the jti claim), and server-side these IDs can be matched against this blacklist. When you log out, you send a request to the service that your current token be blacklisted.
Because JSON Web Tokens are short-lived, the blacklist need only contain tokens valid for validity period plus a few seconds and remains very small (often empty).
If you use JWT to allow authorization on several server, then you do need to distribute this blacklist, so it is not a completely trivial solution. In the simplest scenario you might suffice with only maintaining a blacklist on the server that can refresh tokens (this means that when the token expires, a new one cannot be automatically acquired).
The none issue was highlighted by Tim McLean 2 years ago [0] and comes up in any trivial search about JWT. Surprised that anyone who chooses to use JWT is still getting caught by it as, as you say, any half decent library mitigates this.
For me, the log out / cross device session management issue seems to force a pattern of short expiry with self refreshing tokens. Commonly used devices feel always logged in, whereas uncommonly used devices end up needing a fresh log in each time.
In terms of invalidation, I think a case-by-case basis is best, as it often is.
For example -
If some critical part of your app depends on a user's account or session being still valid, just do the check on that endpoint call (grab the sub/ID claim from the JWT and hit the DB, or similar).
The rest of the time - viewing stats/feed/whatever, admit that if the user had a valid token issued to them 5 minutes ago, it's probably OK to send them stats without having to check revocation (or whichever benefit of JWT you're exploiting).
Exactly. The session invalidation has to happen using a session store or expiry header or something similar. In this regard JWT is not better than cookies.
session invalidation is actually very easy to implement. Its important to think of it as a process instead of a builtin to the standard.
In most of our implementations we achieve this by differentiating between the session token and a request token. Requests that actually power the app use tokens that are very short lived. Request tokens are generated by the core auth server using the session token. A session can be invalidated at the core auth server which will then refuse to give request tokens to the bearer.
Come on. By all means, criticize flawed implementations containing bugs and security holes, but drop the attention-seeking behavior of screaming loudly about how an entire standard is [insert string of superlatives here related to "worthless" and "broken"]. If you're going to make such incredibly strong claims, your arguments had better be up to snuff.
With good implementations (plenty of which exist), and careful usage (via good coding and design habits), JWT is a fine standard and it can save a solid amount of time when constructing the security portions of a system.
Shouting about how something is 100% flawed and should be cast into the flames may get you plenty of views and outrage cred, but (thankfully) it doesn't say much about the veracity of your analysis.
This article is slightly misleading. One should ALWAYS be suspect of any article that states X is always bad and should be avoided. Google, Facebook, Microsoft and hundreds of other companies are using JWT in security critical software. If you've ever logged into an app with Google, you've used JWT.
All I see here is the author complaining about poorly implemented JWT libraries. It's not a problem with the spec, it's a problem with the implementation. XML-DSIG suffered from a number of similar issues and was arguably less secure than JWT because of the massive attack surface provided by all the specifications layered on top of each other.
Here's how you can use JWT Safely:
1. Standardize on what's allowed in the alg header and validate it, don't rely on the JWT library you're using to do it for you.
2. Make sure you're using a high quality JWT library, jwt.io keeps a list of JWT implementations and highlights gaps.
3. Understand that bugs in code related to token generation and verification can and lead to compromise of your application and potentially your user's data. Treat such code with great care.
It would really help encourage the uptake of better alternatives like libsodium if it were standardized. Just referencing some random library can scare decision makers; whereas referencing an IETF official document or ISO standard makes them just take it as given.
The same problem exists with serialization formats - you have XML and JSON, both of which are standardized and have an "official face", although JSON was not born that way. Google protocol buffers are quite superior in many ways, yet as they are just some product of some company and not an actual standard, decision makers are scared of them.
Technology experts do not get to make all the technical decisions, so standardization matters, even if for the stakeholder feelgood factor!
> Why would an issuer ever let a client decide what algo to use?
JWT, like SAML, is made to support separate identity providers and the service providers. In the spirit of generality, this means the identity provider(s) could be from a different vendor, operated by a different organization. E.g., you could let users access their account on your service based a token issued from Google. But that means Google chooses the algorithm, not you!
And it's a standard, so you don't have to write any code of your own. Just import the right middleware for your framework and you're set!
So the temptation is there for library authors to support all the defined algorithms, and just enable everything by default to be as compatible as possible - after all, you can just look at the header to see which algorithm to use!
I'm really confused by this post, a signed JWT is issued by the identity provider (or API end point) and is then validated again by the API end point when part of an API call, usually as a bearer token in the header. The validation of the signed JWT is done via the API.
The approach I use is to have a 'use once' refresh token (long timeout) and a security token (short time out) and JTIs to hold a list of logged out/invalid (refresh token used twice) security token IDs.
Complaining about OAEP when RSA-OAEP is perfectly safe seems needlessly straw-grasping, the other complaints (should) stand perfectly well on their own.
I've used JWT in three languages and the API has always sucked, really badly. I always end up with a verbose heap of gunk - and in some cases, like jwt-go, there is not even a complete example of use in the README + docs. mfw. It should not take multiple steps to sign or verify a signature.
That post is great work. Thanks again. But I think you're wrong about JWT.
The problem with JWT/JOSE is that it's too complicated for what it does. It's a meta-standard capturing basically all of cryptography which, as you've ably observed (along with Matthew Green), was not written by or with cryptographers. Crypto vulnerabilities usually occur in the joinery of a protocol. JWT was written to maximize the amount of joinery.
Good modern crypto constructions don't do complicated negotiation or algorithm selection. Look at Trevor Perrin's Noise protocol, which is the transport for Signal. Noise is instantiated statically with specific algorithms. If you're talking to a Chapoly Noise implementation, you cannot with a header convince it to switch to AES-GCM, let alone "alg:none". The ability to negotiate different ciphers dynamically is an own-goal. The ability to negotiate to no crypto, or (almost worse) to inferior crypto, is disqualifying.
A good security protocol has good defaults. But JWT doesn't even get non-replayability right; it's implicit, and there's more than one way to do it. Application data is mixed with metadata (any attribute not in the JOSE header is in the same namespace as the application's data). Anything that can possibly go wrong, JWT wants to make sure will go wrong.
It's 2017 and they still managed to drag all of X.509 into the thing, and they indirect through URLs. Some day some serverside library will implement JWK URL indirection, and we'll have managed to reconstitute an old inexplicably bad XML attack.
For that matter, something crypto people understand that I don't think the JWT people do: public key crypto isn't better than symmetric key crypto. It's certainly not a good default: if you don't absolutely need public key constructions, you shouldn't use them. They're multiplicatively more complex and dangerous than symmetric key constructions. But just in this thread someone pointed out a library --- auth0's --- that apparently defaults to public key JWT. That's because JWT practically begs you to find an excuse to use public key crypto.
These words occur in a JWT tutorial (I think, but am not sure, it's auth0's):
"For this reason encrypted JWTs are sometimes nested: an encrypted JWT serves as the container for a signed JWT. This way you get the benefits of both."
There are implementations that default to compressed.
There's a reason crypto people table flip instead of writing detailed critiques of this protocol. It's a bad protocol. You look at this and think, for what? To avoid the effort of encrypting a JSON blob with libsodium and base64ing the output? Burn it with fire.
For my current use-case, one of the appealing things about JWT is there are libraries for just about every language, which makes it easy for 3rd party developers to integrate with my service.
Are there any better alternatives to JWT that have implementations in many languages?
If not, elsewhere in this thread tptacek and others have suggested essentially `base64_encode(crypto_auth(json_encode(object)))` would be sufficient... is there any reason not to just slap a name on that "standard" and publish a bunch of libraries?
> is there any reason not to just slap a name on that "standard" and publish a bunch of libraries?
It was called JWT.
jwt.decode(token, 'secret', algorithms=['HS256'])
That's the Python for JWT; encode is similar. You can try something like what you suggest, but the devil is in "object": want your token to expire after a finite amount of time? You'll need to encode that yourself. Token need to be valid only for certain cases? You'll need to encode that yourself. Essentially, you end up reinventing the part of JWT that is relevant to your use-case, and hopefully, arrive at a decent API.
At least in Python, python-jose's APIs will check not only the signature, but these additional claims (expiration of the token, that the token is applicable to the use we're verifying it for).
(I still think we should be moving towards a common API (and JWT is good enough) and building libraries around that standard. They're going to fall short in some ways at first, and I wish people would help improve them. The suggestion of using base64/libsodium feel dangerously close to "rolling your own", because its too low-level for the purpose at hand.)
So JWT is bad because there are bad implementations and there are dumb people who shoot their feet^W^W^Wdon't force alg. Seems like doing software development for 13 years leads to serious problems with logic. There is also confusion between sessions and session storage. Meh..
I hear where you're coming from... but this is also the bane of developer existence. We all have to accept that, every year, tens of thousands of new developers looking for jobs enter the market. There's such a demand for developers that these people get jobs. So footguns, as much as we like to play high-and-mighty and say, "well, duh, don't shoot yourself in the foot" are a real, existential risk to a lot of companies.
A standard that best case doesn't explain the risks properly (so many implementers get it wrong) and worst case prescribes dangerous behavior isn't a very good standard. Especially in a field where many developers are told over and over again to rely on standards, it really should spell out even tiny issues.
One advantage I think not mentioned by some of the linked articles is that the JWT's claims are readable on the client.
It's a pretty good plus, for me: no additional round-trips to the server to grab key user details, which can be put into claims, or check access levels (via roles, permissions, or other types of claim).
This doesn't discount the disadvantages, of course.. I think as with everything it's a case of the right tool for the job. "Depends on the use case".
You've already been to the server once, if you terri-bad app design requires you to go twice that's more your problem than a "feature" of a broken session system.
Is using none a bit like using http instead of https? The standards support it, but it's 2017 so we shouldn't do it.
What I like about JWT's concept is it's completely distributed authorisation: there's no call to a central identity provider. Thus a SPA can pull initial security info from its server, and then fire out requests to different APIs. As long as the API endpoints have the SPA server's public key, they can verify everything without calling it or another central server.
Having said that, I'm not able to discern whether it's secure enough to be workable, so I only know to mandate a list of good algorithms on the API endpoints and to use SSL :) I'll have to read about this session stuff.
EDIT: I wonder if in bigger projects, a message bus or in-memory cache could signal a token blacklist once the user logs/times out of the original server? Or as some others have said, just have short expiry times and ping the SPA server for new tokens every couple of minutes.
I use JWT in a couple of projects and it never once occurred to me to let the client decide the algorithm. I am not sure what use-case would necessitate something like that.
Can anyone think of some criticism for simply storing an API key and secret in localstorage for a web client? It's 50% bridging the gap between using cookies and a normal API and 50% simplifying frontends. The scheme I'm currently using on a project goes like this:
1. Web client ("offline-first" SPA app) hits HTTPS backend in with username and password
2. Web client receives a a generated API key and secret, which expires in a week/month/whatever.
3. That API key and secret gets stored in localstorage on the client-side by the web app for future use (as long as they're logged in)
4. Web client includes the API key and header in requests to the HTTPS backend of the app.
Of course, there are more specifics that could be added like device fingerprinting, invaliding old web-created tokens when a new one is created, and classifying api keys/secrets to certain devices, but I think those things are ancillary.
This is obviously very very close to what a cookie would be, and the only way I could see it going catastrophically wrong is the browser being compromised (whether the vector is XSS, or some other leaky surface on the user's computer). Regular cookies and JWT have the same issues.
I can't think of a failure mode that's any worse than HTTPS cookies or JWT, and it is dead simple. I've really been trying to find some flaws in that plan lately but I can't.
Perhaps I am missing something but I really don't see the point of storing it in localStorage or sessionStorage over cookies what so ever.
1. You have to write code to provide the authentication values in all requests.
2. The GET request for the initial page render can't possibly be authenticated.
Why not cookies? Other than that I agree. I really don't see the point of following the JWT spec or using an implementation of it when it has been shown that these implementations are poor (problems with none algorithm & asymmetric keys).
Fundamentally, what we are talking about is simply a claimed identity, verified and signed by your backend. This is a sound principle. Just implement that and your attack surface is considerably smaller.
I think that JSON Web Tokens (like most things involving JSON) are ill-thought-out, and they can definitely be a bit of a foot-gun, but they are also useful.
I do take issue with the idea that they're not good for stateless authentication: I think they're great when used as short-lived authentication tokens (which don't require serve state) with accompanying long-lived refresh tokens (which do require server state). E.g. a system in which auth tokens are good for an hour and refresh tokens are good for longer (and a refresh token can be refreshed) offer a pleasing user experience (in the normal case, one need never log back on) while also preserving security (revocation takes at most an hour to come into effect). The business gets to make the economic decision about the tradeoffs between risk and cost, deciding whether auth tokens should last for a day, an hour, a minute or a second. I don't think this is 'congratulations, you've reinvented stateful sessions'; rather, it's a well-designed system.
I do wish that JWTs had been better designed, and I wish that folks didn't have to be so careful using the libraries which support them.
[+] [-] StevePerkins|9 years ago|reply
(1) Criticizing vulnerabilities in particular JWT libraries, as in this article.
(2) Generally criticizing the practice of using any "stateless" client tokens. Because there's no great way to revoke them early while remaining stateless, etc.
The problem is that both of these groups only criticize, neither of them can ever seem to actually recommend any alternatives.
I could care less about JWT per se. I'm happy to implement a similar pattern with something else (e.g. store a secure cookie post-auth, skip all the refresh business and just let it expire when it expires, and employ an ugly revocation strategy only if absolutely necessary). I don't need JWT for this.
If I'm providing a REST API, then I'd prefer a token string that I could pass as a header value rather than forcing the use of cookies. Although I suppose you could argue that a cookie is just another header value.
Either way, if you're serving up a REST API to a JavaScript UI... what's NOT a good option is server-side session state (e.g. Java servlet sessions). That requires you to either: configure your load balancer for sticky-sessions, or employ a solution to share session state across all your server-side instances (which never works very reliably). Moreover, relying on a session isn't a very RESTful auth strategy in the first place.
So if I'm writing a SPA in 2017, then I'm definitely taking a client-side approach and running afoul of the #2 critics. And since JWT is so widely implemented (e.g. if I use a "Login with Google" option then I'm using JWT), I'm probably running afoul of the #1 critics too.
These criticism are fine, I guess. There's no faster route to blog clicks, book sales, speaker invites, and consulting dollars than: (1) telling everyone to jump on this year's hype train, or (2) telling everyone that last year's hype train sucks. What the world really needs is a bit more actual prescriptive recommendations of what to do instead.
[+] [-] akfish|9 years ago|reply
But when is the last time we see any technology successfully prevented people from being silly?
[+] [-] sgift|9 years ago|reply
You can never stop someone sufficiently motivated to shoot himself in the foot from doing it. But you can make it harder for those who would do it be accident by providing more safety features - in case of security this is usually seen as a good idea (safe defaults etc.)
[+] [-] revelation|9 years ago|reply
Do not give people options, do not allow algorithmic flexibility, do not have fallbacks, do not have backward compatibility, do not allow "testing" or "insecure" options, do not have complex state machine behavior.
All of these things are exactly what JWT or other "design by commission" standards like SSL suffer from and they have predictably lead to ongoing, at times unfixable security problems.
[+] [-] ponytech|9 years ago|reply
[+] [-] nallerooth|9 years ago|reply
It's a good thing that cookies have never been used in a bad manner. /sarcasm
[+] [-] RegEx|9 years ago|reply
[+] [-] scandox|9 years ago|reply
Probably I can achieve the same overall system with cryptographically secure session cookies, that are persisted in a database, or other store that is accessible across multiple servers. I guess it would amount to the same thing.
Originally I implemented it because:
* My systems are SPA's. Totally JS dependent from the word go.
* I felt like there would be some advantages to being able to establish certain claims without verification. Say for display purposes prior to server comms (show a list of multiple available sessions for example)...In practise this hasn't really been true. Generally I find in the end I am always checking and verifying anyway - without any huge overhead.
* I've always had a sort of fuzz of uncertainty about Cookies. They always felt a bit out of my hands. Thinking it about rigorously of course, people can switch off JS. They can switch off persistence.
* All my user's local data can be persisted in one place, rather than having to store a reference in the Cookie and then lookup in localStorage. In reality though the code for this is pretty trivial...
So overall while I don't know how right he is, I feel like maybe he has a point. Why not just use cookies?
Maybe it's just because as a JS dev, I want everything to stay within a JS universe...and for some reason Cookies have always felt outside of that to me.
[+] [-] Klathmon|9 years ago|reply
I tried to do the right thing, use HTTP-only cookies set over an HTTPS endpoint only to find that it's stupidly complicated and has a lot of annoying edge cases. Turns out iOS's webviews don't like them, iOS in general doesn't like them to be on api.hostname.com if the app is on app.hostname.com, you can't validate if you are logged in or not without doing a web request (which is annoying as hell if you are trying to keep a "logged in" state in something like a react app), you need to deal with a bunch of stupid flags to get the damn browser to even let them go across domains, and a hell of a lot of other annoyances that I can't remember right now.
We are most likely moving to something like JWTs (stored in localstorage or indexeddb) soon because of these issues.
[+] [-] lobo_tuerto|9 years ago|reply
[+] [-] throwaway2016a|9 years ago|reply
Because in a highly distributed system hitting a database to validate authorization is expensive and causes bottlenecks.
A cookie that requires you to hit the database does not solve that issue. Although if the cookie was signed some way that can be cryptographically verified then great. But then you are essentially re-implementing something you could be doing in a standard way instead.
[+] [-] technion|9 years ago|reply
And now there are difficulties around the fact they cannot update an RFC which people will refer to for years.
It's not a vulnerability in one or two libraries - it looks like just about every made the same mistake, which points to something much more broken.
[0] https://auth0.com/blog/critical-vulnerability-in-json-web-en... [1] https://www.ietf.org/mail-archive/web/jose/current/msg05613....
[+] [-] jacopofar2|9 years ago|reply
As long as the problem is known to the developers and the key is specified, I think the biggest issue of JWT is the lack of session invalidation (that is, if you log out your already emitted tokens are still valid until their expiration), but it's a good tradeoff for not having server sessions.
[+] [-] Freak_NL|9 years ago|reply
Because JSON Web Tokens are short-lived, the blacklist need only contain tokens valid for validity period plus a few seconds and remains very small (often empty).
If you use JWT to allow authorization on several server, then you do need to distribute this blacklist, so it is not a completely trivial solution. In the simplest scenario you might suffice with only maintaining a blacklist on the server that can refresh tokens (this means that when the token expires, a new one cannot be automatically acquired).
[+] [-] _puk|9 years ago|reply
For me, the log out / cross device session management issue seems to force a pattern of short expiry with self refreshing tokens. Commonly used devices feel always logged in, whereas uncommonly used devices end up needing a fresh log in each time.
0: https://www.chosenplaintext.ca/2015/03/31/jwt-algorithm-conf...
[+] [-] kierenj|9 years ago|reply
For example -
If some critical part of your app depends on a user's account or session being still valid, just do the check on that endpoint call (grab the sub/ID claim from the JWT and hit the DB, or similar).
The rest of the time - viewing stats/feed/whatever, admit that if the user had a valid token issued to them 5 minutes ago, it's probably OK to send them stats without having to check revocation (or whichever benefit of JWT you're exploiting).
Thing is, this at least gives you the /option/..
[+] [-] StreamBright|9 years ago|reply
[+] [-] batoure|9 years ago|reply
In most of our implementations we achieve this by differentiating between the session token and a request token. Requests that actually power the app use tokens that are very short lived. Request tokens are generated by the core auth server using the session token. A session can be invalidated at the core auth server which will then refuse to give request tokens to the bearer.
[+] [-] cptskippy|9 years ago|reply
[+] [-] camdenlock|9 years ago|reply
Come on. By all means, criticize flawed implementations containing bugs and security holes, but drop the attention-seeking behavior of screaming loudly about how an entire standard is [insert string of superlatives here related to "worthless" and "broken"]. If you're going to make such incredibly strong claims, your arguments had better be up to snuff.
With good implementations (plenty of which exist), and careful usage (via good coding and design habits), JWT is a fine standard and it can save a solid amount of time when constructing the security portions of a system.
Shouting about how something is 100% flawed and should be cast into the flames may get you plenty of views and outrage cred, but (thankfully) it doesn't say much about the veracity of your analysis.
[+] [-] davewritescode|9 years ago|reply
All I see here is the author complaining about poorly implemented JWT libraries. It's not a problem with the spec, it's a problem with the implementation. XML-DSIG suffered from a number of similar issues and was arguably less secure than JWT because of the massive attack surface provided by all the specifications layered on top of each other.
Here's how you can use JWT Safely:
1. Standardize on what's allowed in the alg header and validate it, don't rely on the JWT library you're using to do it for you.
2. Make sure you're using a high quality JWT library, jwt.io keeps a list of JWT implementations and highlights gaps.
3. Understand that bugs in code related to token generation and verification can and lead to compromise of your application and potentially your user's data. Treat such code with great care.
[+] [-] iofiiiiiiiii|9 years ago|reply
The same problem exists with serialization formats - you have XML and JSON, both of which are standardized and have an "official face", although JSON was not born that way. Google protocol buffers are quite superior in many ways, yet as they are just some product of some company and not an actual standard, decision makers are scared of them.
Technology experts do not get to make all the technical decisions, so standardization matters, even if for the stakeholder feelgood factor!
[+] [-] fcvarela|9 years ago|reply
Why would an issuer ever let a client decide what algo to use?
"Send a header that specifies the "HS256" algorithm when the application normally signs messages with an RSA public key."
Again, under what circumstances would a header be used by the client to ask for a specific implementation?
What about encrypted client side cookies - would you let the client "send a header" to specify which key to use???
The only problems you highlighted are serious input validation issues and a naive, broken trust model.
[+] [-] tveita|9 years ago|reply
JWT, like SAML, is made to support separate identity providers and the service providers. In the spirit of generality, this means the identity provider(s) could be from a different vendor, operated by a different organization. E.g., you could let users access their account on your service based a token issued from Google. But that means Google chooses the algorithm, not you!
And it's a standard, so you don't have to write any code of your own. Just import the right middleware for your framework and you're set!
So the temptation is there for library authors to support all the defined algorithms, and just enable everything by default to be as compatible as possible - after all, you can just look at the header to see which algorithm to use!
[+] [-] detaro|9 years ago|reply
If these things are suggested in the standard and promptly followed by major implementations, then the standard isn't very good.
[+] [-] unknown|9 years ago|reply
[deleted]
[+] [-] draw_down|9 years ago|reply
Right, so, why is this in the spec?
[+] [-] awjr|9 years ago|reply
The approach I use is to have a 'use once' refresh token (long timeout) and a security token (short time out) and JTIs to hold a list of logged out/invalid (refresh token used twice) security token IDs.
[+] [-] regecks|9 years ago|reply
I've used JWT in three languages and the API has always sucked, really badly. I always end up with a verbose heap of gunk - and in some cases, like jwt-go, there is not even a complete example of use in the README + docs. mfw. It should not take multiple steps to sign or verify a signature.
[+] [-] tptacek|9 years ago|reply
[+] [-] asanso|9 years ago|reply
[+] [-] tptacek|9 years ago|reply
The problem with JWT/JOSE is that it's too complicated for what it does. It's a meta-standard capturing basically all of cryptography which, as you've ably observed (along with Matthew Green), was not written by or with cryptographers. Crypto vulnerabilities usually occur in the joinery of a protocol. JWT was written to maximize the amount of joinery.
Good modern crypto constructions don't do complicated negotiation or algorithm selection. Look at Trevor Perrin's Noise protocol, which is the transport for Signal. Noise is instantiated statically with specific algorithms. If you're talking to a Chapoly Noise implementation, you cannot with a header convince it to switch to AES-GCM, let alone "alg:none". The ability to negotiate different ciphers dynamically is an own-goal. The ability to negotiate to no crypto, or (almost worse) to inferior crypto, is disqualifying.
A good security protocol has good defaults. But JWT doesn't even get non-replayability right; it's implicit, and there's more than one way to do it. Application data is mixed with metadata (any attribute not in the JOSE header is in the same namespace as the application's data). Anything that can possibly go wrong, JWT wants to make sure will go wrong.
It's 2017 and they still managed to drag all of X.509 into the thing, and they indirect through URLs. Some day some serverside library will implement JWK URL indirection, and we'll have managed to reconstitute an old inexplicably bad XML attack.
For that matter, something crypto people understand that I don't think the JWT people do: public key crypto isn't better than symmetric key crypto. It's certainly not a good default: if you don't absolutely need public key constructions, you shouldn't use them. They're multiplicatively more complex and dangerous than symmetric key constructions. But just in this thread someone pointed out a library --- auth0's --- that apparently defaults to public key JWT. That's because JWT practically begs you to find an excuse to use public key crypto.
These words occur in a JWT tutorial (I think, but am not sure, it's auth0's):
"For this reason encrypted JWTs are sometimes nested: an encrypted JWT serves as the container for a signed JWT. This way you get the benefits of both."
There are implementations that default to compressed.
There's a reason crypto people table flip instead of writing detailed critiques of this protocol. It's a bad protocol. You look at this and think, for what? To avoid the effort of encrypting a JSON blob with libsodium and base64ing the output? Burn it with fire.
[+] [-] tlrobinson|9 years ago|reply
Are there any better alternatives to JWT that have implementations in many languages?
If not, elsewhere in this thread tptacek and others have suggested essentially `base64_encode(crypto_auth(json_encode(object)))` would be sufficient... is there any reason not to just slap a name on that "standard" and publish a bunch of libraries?
[+] [-] deathanatos|9 years ago|reply
It was called JWT.
That's the Python for JWT; encode is similar. You can try something like what you suggest, but the devil is in "object": want your token to expire after a finite amount of time? You'll need to encode that yourself. Token need to be valid only for certain cases? You'll need to encode that yourself. Essentially, you end up reinventing the part of JWT that is relevant to your use-case, and hopefully, arrive at a decent API.At least in Python, python-jose's APIs will check not only the signature, but these additional claims (expiration of the token, that the token is applicable to the use we're verifying it for).
(I still think we should be moving towards a common API (and JWT is good enough) and building libraries around that standard. They're going to fall short in some ways at first, and I wish people would help improve them. The suggestion of using base64/libsodium feel dangerously close to "rolling your own", because its too low-level for the purpose at hand.)
[+] [-] ash|9 years ago|reply
1. `crypto_auth` is for secret-key signatures (auth): https://download.libsodium.org/doc/secret-key_cryptography/s...
2. `crypto_sign` is for public-key signatures: https://download.libsodium.org/doc/public-key_cryptography/p...
And tptacek is arguing secret (symmetric) key is preferable: https://news.ycombinator.com/item?id=13866983
[+] [-] idkfa|9 years ago|reply
[+] [-] forgottenacc57|9 years ago|reply
Well.....
[+] [-] keithwhor|9 years ago|reply
[+] [-] detaro|9 years ago|reply
[+] [-] kierenj|9 years ago|reply
It's a pretty good plus, for me: no additional round-trips to the server to grab key user details, which can be put into claims, or check access levels (via roles, permissions, or other types of claim).
This doesn't discount the disadvantages, of course.. I think as with everything it's a case of the right tool for the job. "Depends on the use case".
[+] [-] arethuza|9 years ago|reply
[+] [-] mattmanser|9 years ago|reply
[+] [-] robertlagrant|9 years ago|reply
What I like about JWT's concept is it's completely distributed authorisation: there's no call to a central identity provider. Thus a SPA can pull initial security info from its server, and then fire out requests to different APIs. As long as the API endpoints have the SPA server's public key, they can verify everything without calling it or another central server.
Having said that, I'm not able to discern whether it's secure enough to be workable, so I only know to mandate a list of good algorithms on the API endpoints and to use SSL :) I'll have to read about this session stuff.
EDIT: I wonder if in bigger projects, a message bus or in-memory cache could signal a token blacklist once the user logs/times out of the original server? Or as some others have said, just have short expiry times and ping the SPA server for new tokens every couple of minutes.
[+] [-] fareesh|9 years ago|reply
[+] [-] draw_down|9 years ago|reply
[+] [-] hardwaresofton|9 years ago|reply
1. Web client ("offline-first" SPA app) hits HTTPS backend in with username and password
2. Web client receives a a generated API key and secret, which expires in a week/month/whatever.
3. That API key and secret gets stored in localstorage on the client-side by the web app for future use (as long as they're logged in)
4. Web client includes the API key and header in requests to the HTTPS backend of the app.
Of course, there are more specifics that could be added like device fingerprinting, invaliding old web-created tokens when a new one is created, and classifying api keys/secrets to certain devices, but I think those things are ancillary.
This is obviously very very close to what a cookie would be, and the only way I could see it going catastrophically wrong is the browser being compromised (whether the vector is XSS, or some other leaky surface on the user's computer). Regular cookies and JWT have the same issues.
I can't think of a failure mode that's any worse than HTTPS cookies or JWT, and it is dead simple. I've really been trying to find some flaws in that plan lately but I can't.
[+] [-] mkohlmyr|9 years ago|reply
1. You have to write code to provide the authentication values in all requests.
2. The GET request for the initial page render can't possibly be authenticated.
Why not cookies? Other than that I agree. I really don't see the point of following the JWT spec or using an implementation of it when it has been shown that these implementations are poor (problems with none algorithm & asymmetric keys).
Fundamentally, what we are talking about is simply a claimed identity, verified and signed by your backend. This is a sound principle. Just implement that and your attack surface is considerably smaller.
[+] [-] methyl|9 years ago|reply
[+] [-] mspradley|9 years ago|reply
[+] [-] zeveb|9 years ago|reply
I do take issue with the idea that they're not good for stateless authentication: I think they're great when used as short-lived authentication tokens (which don't require serve state) with accompanying long-lived refresh tokens (which do require server state). E.g. a system in which auth tokens are good for an hour and refresh tokens are good for longer (and a refresh token can be refreshed) offer a pleasing user experience (in the normal case, one need never log back on) while also preserving security (revocation takes at most an hour to come into effect). The business gets to make the economic decision about the tradeoffs between risk and cost, deciding whether auth tokens should last for a day, an hour, a minute or a second. I don't think this is 'congratulations, you've reinvented stateful sessions'; rather, it's a well-designed system.
I do wish that JWTs had been better designed, and I wish that folks didn't have to be so careful using the libraries which support them.