6 ms·
This exact vulnerability is something I've seen in a good number of open-source codebases or boilerplate repos in the Node ecosystem. The library most people u
by gavinray 6y ago
This exact vulnerability is something I've seen in a good number of open-source codebases or boilerplate repos in the Node ecosystem.
The library most people use for JWT stuff in Node is Auth0's. There are two methods for decoding a token payload: jwt.decode() and jwt.verify()
Both of them return the decoded payload, but one (if you don't read the documentation) sounds more immediately like the one you think you want to use.
jwt.decode() doesn't verify the token when decoding:
https://github.com/auth0/node-jsonwebtoken#jwtdecodetoken--options https://github.com/auth0/node-jsonwebtoken#jwtdecodetoken--o...
If you dig through Node repos on Github searching for "jwt.decode()" or "this.jwtService.decode()" you'll see a shocking number of results.
The other big mistake I've seen is encoding personal data in the token, instead of just an ID that only has meaning inside of your database. It turns out not everyone is aware that JWT tokens are publicly decodable and that the only security is in the signing + verification. Many people I've spoke with think the token is like a hash.
- azinman2 6y agoI saw a set of junior devs implementing this thinking it was encryption, and not understanding the difference. I feel like the main JWT page needs a big warning that says “this is not encryption, but a way to verify the contents have not been modified by anyone but you”
- gavinray 6y agoHey, I can't deny that was me 5 years ago. I was totally putting emails and other personal info into JWT's because "Hey, it's encrypted". Live and learn haha But yeah, definitely some lack of awareness around how JWT's work + best practices. I think that Auth-as-a-Service platforms and the "npm install" culture aren't helping this at all. In recent years from conversations with other devs, it seems like many of them have never written an auth system themselves + couldn't do it if you asked. Coming from an era where rolling your own token-auth setup, or on larger projects even custom OAuth providers, this is both a bit mindblowing and kind of scary.
- chrisjarvis 6y ago> The other big mistake I've seen is encoding personal data in the token, instead of just an ID that only has meaning inside of your database. It turns out not everyone is aware that JWT tokens are publicly decodable and that the only security is in the signing + verification. Many people I've spoke with think the token is like a hash. I have been working as a software engineer professionally for 3 years (the entire time with web technologies) and I learned this like 4 months ago... I think there needs to be more awareness of this.
- mdaniel 6y agoAnytime one sees base64 text, have a little lookie at the decoded version, as there are usually all kinds of fascinating things that people will "encrypt" in b64
- tialaramex 6y agoAnd you aren't the only one poking around in such weakly obfuscated data. Part of the driving force behind the IETF's enthusiasm for end-to-end encryption is not high minded principles of privacy (though there certainly are plenty of people who care, not just from the EFF and ACLU) but engineers frustrated that protocols get ossified by idiots decoding packets and guessing what to allow rather than reading the documentation. If you encrypt everything, these idiots can't tell what is what and so they either block everything (which at least has the benefit of being obvious) or they give up and stop trying to do the impossible. Hooray. The idiots also write passive aggressive "informational" documents about how the sky is falling because of all this encryption, but you get used to those.
- deleted 6y ago[deleted]
- kochthesecond 6y agoI am curious, did you never even have a look at the spec?
- chrisjarvis 6y ago
- hinkley 6y agoI worked on some code signing code, and one of the internal customers, who had a lot of clout (but not as much as they thought) were adamant that I needed to provide them a way to pluck data out of the payload without verifying the signature first. I told them, in a variety of extremely diplomatic ways, to politely fuck off. In fact I did a sweep of the code to make extra sure that none of the data paths gave you anything before verification had finished (there were not barn doors but there were soft spots). When your dog is sniffing around, it's time to hide the treats. The only reason you want to look at a payload is to make decisions about it, before you can trust those decisions are rational. What I did promise them is that I would continue to try to make the checks cheaper, which we did. Ten years later, I still trust that I made the right call. Never expose a function from a security library that gives you the data without verifying it first. You are doing violence to the user, the team, the company, possibly an entire industry.
- gavinray 6y agoIn this vein I wonder if it wouldn't be a bad choice to underscore the non-verified decode methods in token API's. Surely people would still abuse them but at least there's an immediate visual warning if you choose not to read the docs, "Why is this method underscored but the other one not?"
- hinkley 6y agoIt's still booby-trapping. I'm finding as I get older that a lot of programmers use their own mistakes to rationalize why they are the only ones who should be trusted with certain things. Well, of course I'm in charge. Last time Steve did something he pushed the big red button that shut down the whole server room. If I weren't in charge, then it would just be "Steve"s everywhere. Anarchy. Who put the red button there? Who thought having the big red button there might be a stupid idea? That's not important. What's important is that Steve fucked up and I didn't. Remember: never trust Steve. When people sit down to write open source, they write it the same way they would write code at work, because they've either never experienced anything better, or it was drowned out by the din. So their OSS is always almost as toxic as the situation I illustrated above. If, for some reason, you want to leave dangerous things laying around, you need way more safety interlocks than an underscore. If you should never call a function, what's the harm in making it expensive to call? Use a function name where the only reasonable interpretation of calling it is that the developer consented, with full knowledge. Make the function name 60 characters long with some colorful adjectives. Name it after the OWASP recommendation that says what a bad fucking idea it is to call this method. Giant neon lights. Fireworks. And a marching band. Do not look into laser with remaining eye.
- tialaramex 6y agoMmm. 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 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?
- hn_throwaway_99 6y agoI 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 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?
- Filligree 6y agojwt.decode simply shouldn't exist at all, or rather, shouldn't be public.
- statictype 6y ago> The other big mistake I've seen is encoding personal data in the token, You’re right that this is a big mistake but I also thought this was in fact one of the primary allures of JWT - an attempt (misguided) to make session management stateless and avoid that database roundtrip on the server end?
- jimktrains2 6y agoThis has been my experience, and the issue of figuring out if a token has been revoked is usually punted on.
- halfmatthalfcat 6y agoTo your last point, there should be more education in JWS v. JWE. Implementing JWE isn't hard and it should be the defacto standard.
- asperous 6y agoThey could rename it to unsafeDecode or similiar. Yaml had a similar design problem where decoding something could execute code which was unsafe. The solution was to leave the function but change the name.
- equidistant 6y agoI've raised a PR to rename decode() to unsafeDecode() (removing it from the public API might be a hard sell). I really have no idea why this is part of the public API. https://github.com/auth0/node-jsonwebtoken/pull/741 https://github.com/auth0/node-jsonwebtoken/pull/741
- patkai 6y agoPlease, everyone, do this more often! So simple and so powerful.