Thank you for the fantastic summary James. You’re spot on about the various implementation issues that plague JWT libraries.
While I think it’s an OK technology if you use a very explicit subset and you know what you’re doing (see https://github.com/google/jws) it is indeed a bit of a minefield and I’m not sure we should be promoting it. That being said, are signed cookies really a suitable replacement for JWTs? Right off the bat there is a size limit that’s shared with other cookies on your domain, and you might not want to (or be able to) encode the data in a cookie to begin with. Maybe we can update the docs to show how you you would might use some of the signing primitives instead of JWTs, but this also sounds a bit dangerous 🤷♂️ >> On 27 Apr 2020, at 03:53, James Bennett <ubernost...@gmail.com> wrote: > On Sun, Apr 26, 2020 at 8:46 AM Adam Johnson <m...@adamj.eu> wrote: >> >> James, I too would like to know your criticisms! I've always understood that >> they aren't much different to signed cookies, but I haven't looked too >> deeply at them. > > Well, people asked. So. > > The short summary is: JWT is over-complex, puts too much power in the > attacker's hands, has too many configuration knobs, and makes poor > cryptographic choices. This is why we see vulnerabilities in JWT > libraries and JWT-using systems again and again and again. > > And even if you get every single bit of it right, in the ideal perfect > world with the ideal perfect implementation, the payoff is you've put > in a ton of work to get something that already existed: signed > cookies, for the use case of session identification, or any of several > better token or token-like systems -- everything from PASETO to just > timestamped HMAC'd values -- for the use case of inter-service > communication. > > The longer version goes more like this... > > JWT is a more complex thing than many people appreciate. In fact, it's > at least *five* things, each specified in its own RFC, plus some more > you have to know about and implement if you want any hope of getting > the actually-sorta-secure version. And right off the bat, that's > worrying: the more different things you have to implement, and the > more places you have to look to find out what and how to implement, > the more opportunities there are to make mistakes. > > This complexity comes from the sheer number of different options JWT > tries to support, which in turn is an anti-pattern. JWTs may be > signed, or they may not. They may be encrypted, or they may not. There > are multiple different options for how to sign, how to encrypt, how to > manage and specify keys... in a well-designed system there would be > far fewer options. Ideally, there'd be only one option, and the > solution for a vulnerability being found in it would be to increment > the version of the underlying spec, and change to something > better. > > Anyway. In JWT, signature and encryption schemes are effectively > negotiable, which is yet another anti-pattern: you are putting > enormous power in the hands of attackers to negotiate you down to a > bad, or nonexistent, cipher/algorithm for encryption or signing. TLS/SSL > learned this lesson the hard way; JWT has chosen not to learn it at > all. Worse, JWT embeds the negotiation about how to handle the token > into the token itself. This is just asking for trouble, and in fact > trouble has routinely occurred. As a somewhat sarcastic author of my > acquaintance put it: > >> It is extraordinarily easy to screw up JWT. JWT is a JSON format >> where you have to parse and interpret a JSON document to figure out >> how to decrypt and authenticate a JSON document. It has revived bugs >> we thought long dead, like “repurposing asymmetric public keys as >> symmetric private keys”. > > (from: https://latacora.micro.blog/a-childs-garden/) > > More succinctly: JWTs inherently and unavoidably violate the > Cryptographic Doom Principle > (https://moxie.org/blog/the-cryptographic-doom-principle/). Worse, > JWTs put full control of the violation in the hands of the attacker, > who -- thanks to the high level of configurability JWT offers -- is > free to find the set of options most likely to compromise you, and > foist them on you. > > That quoted line above about revived long-dead bugs is no joke, > incidentally. Here's one from a few years back: > > https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/ > > Five different libraries, written in three different languages, all > had the same bug. I once had the misfortune of arguing with someone > who attributed this to the libraries being built by bad programmers, > or in bad languages. But I personally tend to agree with a line from > this talk: > > https://www.okta.com/video/oktane19-cryptographic-wrong-answers/ > >> Now you can say look those are all implementation vulnerabilities, >> it's not actually JWTs fault, I disagree. If I can find the same >> vulnerability in five popular libraries, then maybe the spec did a >> bad job of making sure people avoided that vulnerability. > > So to completely head off the "it's just bad implementations" > argument, let's turn to the specs themselves: RFCs 7515, 7516, 7517, > 7518, and 7519 are the core specifications that make up with is > commonly called "JWT" (and in RFC-land is more properly called "JOSE" > -- "JSON Object Signing and Encryption", of which the token format is > but one part). > > The JOSE RFCs make a number of choices regarding default sets of > standardized cryptographic options. For example, RFC 7518 standardizes > thirteen signature algorithm options, seventeen encryption key > management options, and six different encryption cipher options. > > This is already a problem -- that's an absolutely gigantic > combinatorial space of options! But then it gets worse. > > Let's look just at the first table of options in that RFC, which is > for signing algorithms. It categorizes them as "Required", > "Recommended+", "Recommended", or "Optional". It then places into its > "Recommended" category options like RSASSA-PKCS-v1_5, which was known > to be vulnerable to Bleichenbacher's attack nine years before this RFC > was written (and Bleichenbacher's attack on PKCS#1 in general had been > known for 17 years at that point). > > And then if we read a bit further we find ECDSA with P-256 is in the > "Recommended+" category, which the RFC helpfully says means that it is > likely to be bumped up to "Required" in the future. The P-256 curve > is... controversial, to say the least, and it took several additional > years before RFC 8037 finally standardized a better alternative > (Ed25519). > > And that's just one quick glance at one table of one set of the > available options in one of the five core RFCs. > > Here's another set of critical vulnerabilities: > > https://blogs.adobe.com/security/2017/03/critical-vulnerability-uncovered-in-json-encryption.html > > Five different libraries, for three different languages (and a > *different* set of libraries and languages than the previous > critical-vulnerability post I linked), all vulnerable to the same > basic invalid-curve attack. > > Here's another one from just ten days ago: > > https://insomniasec.com/blog/auth0-jwt-validation-bypass > > Auth0's JWT validation was tricked into accepting unsigned tokens > thanks to a bug in parsing the (attacker-provided and > attacker-selected!) "alg" header parameter. > > I could go on with this, but the general idea I'm trying to get across > is: JWT's issues are not just due to specific implementations being > bad. Several are issues that come with JWT itself, and are baked into > its design and specifications. The existence of vulnerabilities in > popular libraries is thus an expected consequence; no amount of > brilliance on the part of library authors can correct for the inherent > problems with JWT. > > Meanwhile, we have access to alternatives that are simpler, more > robust, or often both. Django already supports at least two of them > out-of-the-box. As a result, I remain *strongly* against implementing > support for JWTs in Django, in any form, even the draft subset > implementation Claude has posted. > > -- > You received this message because you are subscribed to the Google Groups > "Django developers (Contributions to Django itself)" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to django-developers+unsubscr...@googlegroups.com. > To view this discussion on the web visit > https://groups.google.com/d/msgid/django-developers/CAL13Cg8FkiPVi8oCuxtBUsiDoOUezXa%2B%2Bv5b75QxcZoDUtxy7A%40mail.gmail.com. -- You received this message because you are subscribed to the Google Groups "Django developers (Contributions to Django itself)" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-developers+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-developers/873A28BE-2B12-48F6-9B94-B23AB4A798B4%40tomforb.es.