Re: Generate JWTs with Django
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 wrote: > On Sun, Apr 26, 2020 at 8:46 AM Adam Johnson 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 d
Re: Generate JWTs with Django
I completely agree with James. I felt dread when I saw a JWT Thread appear as, for me synonymous with flaws security and I'd rather Django stay well clear of them On Monday, 27 April 2020 03:53:39 UTC+1, James Bennett wrote: > > On Sun, Apr 26, 2020 at 8:46 AM Adam Johnson > > 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 > stand
Re: Generate JWTs with Django
Thank you very much James. I've learned once again that "everyone is using it" does not make it good. (Would love if you pasted your write up on your blog to make it easier to share) On Mon, 27 Apr 2020 at 10:37, Steven Mapes wrote: > I completely agree with James. I felt dread when I saw a JWT Thread appear > as, for me synonymous with flaws security and I'd rather Django stay well > clear of them > > On Monday, 27 April 2020 03:53:39 UTC+1, James Bennett wrote: >> >> On Sun, Apr 26, 2020 at 8:46 AM Adam Johnson 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
Re: Fellow Reports - April 2020
Week ending April 26, 2020. *Triaged:* https://code.djangoproject.com/ticket/31480 - Accessing admin panel doesn't work. (worksforme) https://code.djangoproject.com/ticket/31481 - Admin crash when using functions in model meta ordering of o2o primary key. (fixed) https://code.djangoproject.com/ticket/31483 - Remove admin change_form.js dependency on jQuery. (accepted) https://code.djangoproject.com/ticket/31484 - Possibility to provide additional Context to Render a FlatPage. (wontfix) https://code.djangoproject.com/ticket/31478 - Template.get_exception_info() relies on internal state which isn't correct for sub-templates. (duplicate) https://code.djangoproject.com/ticket/31485 - Update admin's jQuery to 3.5.X. (created) https://code.djangoproject.com/ticket/31489 - Django Admin showing "Date input" for Time Field in Mobile Safari. (duplicate) https://code.djangoproject.com/ticket/31492 - Changing field type can cause unrelated nullability change in field on Oracle. (created) https://code.djangoproject.com/ticket/31491 - dbshell command for MySQL backend uses "passwd" instead of "password". (accepted) https://code.djangoproject.com/ticket/31496 - Combined queryset crash when chaining `values()` after `order_by()` with annotated constantants. (accepted) https://code.djangoproject.com/ticket/31499 - Store ModeState.fields into a dict. (accepted) https://code.djangoproject.com/ticket/31497 - get_static_prefix() as variable in a template doesn't work. (worksforme) https://code.djangoproject.com/ticket/31498 - GenericRelation's get_internal_type() incorrectly reports "ManyToManyField". (wontfix) https://code.djangoproject.com/ticket/31500 - Allow QuerySet.in_bulk() for fields with total UniqueConstraints. (accepted) https://code.djangoproject.com/ticket/24691 - Document model._state.adding (since UUIDField sets value before save) (duplicate) https://code.djangoproject.com/ticket/31502 - Document Model._state.db and Model._state.adding. (accepted) https://code.djangoproject.com/ticket/31506 - ExpressionWrapper() doesn't respect output_field when combining DateField and timedelta on PostgreSQL and MySQL. (accepted) https://code.djangoproject.com/ticket/31507 - Augment QuerySet.exists() optimizations to .union().exists(). (accepted) https://code.djangoproject.com/ticket/31505 - Document possible email address enumeration in PasswordResetView. (accepted) https://code.djangoproject.com/ticket/31510 - server is not working properly for admin panel. (duplicate) https://code.djangoproject.com/ticket/31511 - Allow stopwords in slugs generated by ModelAdmin.prepopulated_fields (duplicate) https://code.djangoproject.com/ticket/31512 - Django TextChoices cannot utilize `is` or `==` isn't explicitly stated. (invalid) https://code.djangoproject.com/ticket/31514 - Correct default forms fields in model fields docs. (accepted) *Reviewed/committed:* https://github.com/django/django/pull/12751 - Refs #29069 -- Added test for calling request_finished signal by static file responses. https://github.com/django/django/pull/12756 - Fixed #24559 -- Made MigrationLoader.load_disk() catch more specific ModuleNotFoundError. https://github.com/django/django/pull/12741 - Fixed #31477 -- Removed "using" argument from DatabaseOperations.execute_sql_flush(). https://github.com/django/django/pull/12742 - Disabled management commands output with verbosity 0 in various tests. https://github.com/django/django/pull/12747 - Fixed #31474 -- Made QuerySet.delete() not return the number of deleted objects if it's zero. https://github.com/django/django/pull/12746 - Refs #22463 -- Replaced JSHint with ESLint in contributing docs. https://github.com/django/django/pull/12734 - Fixed #31064 -- Recreated auto-created relationships on type change on SQLite. https://github.com/django/django/pull/12748 - Fixed #31479 -- Added support to reset sequences on SQLite. https://github.com/django/django/pull/12771 - Fixed #31499 -- Stored ModelState.fields into a dict. https://github.com/django/django/pull/12774 - Fixed #31500 -- Fixed detecting of unique fields in QuerySet.in_bulk() when using Meta.constraints. https://github.com/django/django/pull/12708 - Fixed #29224 -- Fixed removing index_together indexes if exists unique_together constraint on the same fields. https://github.com/django/django/pull/12788 - Refs #31369 -- Deprecated models.NullBooleanField in favor of BooleanField(null=True). https://github.com/django/django/pull/12790 - Fixed #31514 -- Fixed default form widgets in model fields docs. *Authored:* https://github.com/django/django/pull/12758 - Fixed #31485 -- Updated admin's jQuery to 3.5.0. https://github.com/django/django/pull/12762 - Updated admin's XRegExp to 3.2.0. https://github.com/django/django/pull/12780 - Fixed #31505 -- Doc'd possible email addresses enumeration in PasswordResetView. Best regards, Mariusz -- You received this message because you are subscribed to the Google Groups "Django d