News for hackers. Stuff that matters.
Re:# of days since the last alg=none JWT vulnerability by tialaramex on Tuesday September 01, 2020 @06:35PM (#24347914)
Mmm. The people who don't like JWT tend to blame JWT here, but this type of mistake is a sharp edge in a library that has no good reason to be there except laziness.

We've been here before with HTTPS. Today the libraries most of you are likely to use to fetch https://example.com/something (such as Python's requests) will without any extra effort default to insisting that the remote server has a certificate for the name example.com from a CA trusted in the Web PKI and knows the associated private key.

But even just ten years ago the equivalent library might have a flag labelled "verify" that defaults off, and it turns out even if you do set that flag you're only causing it to check the server can prove it owns this certificate, not that the certificate is for the name you wanted, or issued by anybody you trust. So even if you jump through hoops it's useless.

That wasn't a bug in TLS, and I'd argue that libraries offering moral equivalents of jwt.decode() isn't a bug in JWT, it's a bug in these libraries. These libraries are garbage, their authors should be ashamed.

Imagine if you got a library with a sort() method and careful reading of the documentation revealed that oops, you actually mustn't call sort() if you want things sorted you need to call trickyOrderingMechanism(ORIENTATION, input, mode_flags) and read sixteen extra pages of documentation because the sort() method just uses the "default" sort of "not sorted at all". Brilliant. Library goes in the trash right?

Re:# of days since the last alg=none JWT vulnerability by hn_throwaway_99 on Tuesday September 01, 2020 @07:02PM (#24348143)
I don't really understand what you're arguing here. I don't think this is a "sharp edge" as much as people fundamentally misunderstanding JWTs. 'decode' seems like the proper term for taking the base64-encoded string and, surprise, decoding it. I mean, you can decode any JWT, without any verification, at https://jwt.io now. If you're calling decode, which doesn't take any kind of public key, how would you except it to do any verification in any case? What exactly would one expect it to verify?

Verify then seems like the proper term for verifying that the JWT was in fact signed by the corresponding private key to the public key you pass that method.

I'm curious, how else would you define these libraries?

Re:# of days since the last alg=none JWT vulnerability by Filligree on Tuesday September 01, 2020 @07:11PM (#24348198)
jwt.decode simply shouldn't exist at all, or rather, shouldn't be public.
Re:# of days since the last alg=none JWT vulnerability by will4274 on Tuesday September 01, 2020 @07:22PM (#24348270)
Not quite. It's normal to decide the header to find the right key. Yes, you can also do this as a callback, but callbacks make for confusion code flow. It's fine for jwt.decode to exist and be public - if it only decodes the header and not the body.
Re:# of days since the last alg=none JWT vulnerability by shakna on Tuesday September 01, 2020 @07:30PM (#24348329)
If it's unverified, then you can't trust the header to begin with. You can't trust that it even forms any kind of valid format. It could be a payload of "naughtystrings" for all you know.

And if you really must decode it, then you can call the base64 decode yourself - and know what you're doing is unsafe.

In the case of an unverified token, it is best to pretend the token doesn't even exist.

Re:# of days since the last alg=none JWT vulnerability by will4274 on Wednesday September 02, 2020 @12:36PM (#24354938)
Literally incorrect. You can't verify the jwt prior to reading the header, because you don't know which of the advertised keys was used to sign the jwt.

Check out e.g. auth0's doc. https://auth0.com/docs/tokens/json-web-tokens/validate-json-...

Re:# of days since the last alg=none JWT vulnerability by shakna on Wednesday September 02, 2020 @06:51PM (#24359126)
I assume you're refering to this part of the spec:

> If the JOSE Header contains a "cty" (content type) value of "JWT", then the Message is a JWT that was the subject of nested signing or encryption operations. In this case, return to Step 1, using the Message as the JWT. [0]

This is also step 8 of validating a JWT. There is a number of validation steps you need to take before you can decide how to process the payload.

You'll also note that none of the previous 7 steps actually decode the payload ("the Message") - they only find it. And 4 of those steps are about verifying that the header isn't dangerous.

[0] https://tools.ietf.org/html/rfc7519#section-7.2

Re:# of days since the last alg=none JWT vulnerability by deathanatos on Tuesday September 01, 2020 @07:52PM (#24348498)
Again, the library can provide that functionality in a better way. In this case, the library could provide a means for the consuming code to be queried about what keys are available. E.g., in JS-like pseudo-code:

  validator = new JwtValidator();
  // By default, the validator should reject everything, until you call…
  validator.add_signing_key(new RsaSigned((a strongly-typed RSA key));
  // I wouldn't even add this to the library, but let's
  // say you want to comply with the RFC fully:
  validator.add_signing_key(new CompletelyUnsafeNoneAlgorithm());
  // (And I'd name it that explicitly, to let the consumer know that
  // what they're doing is nuts.)
This validator knows exactly which algorithms — and keys — are valid.

If the full keyset is somehow not known ahead of time, a callback to enumerate keys of a certain type could be configured.

Better API design here prevents this vuln. from ever happening.

(Personally, I wish the RFC had never added "alg": "none"; it's a mistake waiting to happen. I wish JWS/JWT could be updated to remove it.)

Re:# of days since the last alg=none JWT vulnerability by kochthesecond on Tuesday September 01, 2020 @07:33PM (#24348348)
I am inclined to agree with you, but they could have named it decodeUnsafe()
Re:# of days since the last alg=none JWT vulnerability by diegoperini on Tuesday September 01, 2020 @07:15PM (#24348226)

   jwt.ifAuthentic(callback)
would be a good start. Callback can receive the decoded value and such.