# of days since the last alg=none JWT vulnerability
howmanydayssinceajwtalgnonevuln.com
howmanydayssinceajwtalgnonevuln.com
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--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.
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.
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.
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.
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.
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.
If the symbol is not exposed, then you can't get anywhere in the neighborhood of calling it accidentally. I think if you do enough object introspection you can still get the function handle, but you could never mistake the resulting code for being anything other than farm fresh, Grade-A Cheese.
https://hackage.haskell.org/package/bytestring-0.10.12.0/doc...
You could arguably define another means of out-of-band signalling, though, but it would also be unauthenticated.
Edit: That said, getting the unauthenticated data should be very explicit and impossible to do "accidentally", if the library allows it at all.
Are you essentially talking about having different strategies to verify the token? Would it make sense to provide some sort of filter function as a parameter that the library can call to clarify what operations need to be performed?
That would allow you to peek at the records in a context where your role is clear, and where the code flow makes it awkward to take the data and run with it. If the code feels wrong enough, it's hard for the developer to claim ignorance, and if it's clear from the outset that ignorance is not an explanation, that leaves malice and stupidity. Most developers won't admit to either, but if forced they'd rather be seen as malicious than stupid, and malicious gets you a meeting with HR.
Yes, you could have side effects, but it's pretty damned obvious you're being naughty. That's mostly what I want. The obviousness of the cheating makes people think twice, ask questions. Slow down.
A lot of libraries could be better if the authors spent some time sitting at breakpoints in their own code. You could, I'm sure, arrange a JWT parser so that the data you need for triage is hanging out in a very clearly named stack frame a couple steps into the library.
In my case the format was simple enough that I trained a couple people to be able to inspect these things by hand and tell what went wrong. The happy path for the format was stupid simple. Anyone could have written their own parser for the happy path. It was the rules enforcement that made the code I had worth anything. We were the source of authority, and I took that seriously, on the Precautionary Principle if nothing else (and there were plenty of other reasons).
I don't know what exactly you mean by improving performance by looking at the payload before the cost of signature verification. If you mean that for some reason you could discard large portion of messages without actually verifying the signature then this is generally false.
In a DoS situation the attacker might want to consume your resources without bothering to forge the signature but just as well he can forge the content so potentially easy fix to their fake content will cause you to pay for the signature verification anyway.
If, on the other hand, the application somehow relies on this to be viable then very likely this is a design fault. I can imagine for example that you might want to discard messages with outdated tokens but there are better ways to solve this (just don't send outdated tokens?)
If you decide things without checking with a higher authority, then you are the Confused Deputy, and that typically ends badly. It's not Barney's fault he keeps getting locked in the jail cell. It's Andy's.
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?
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?
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.
Check out e.g. auth0's doc. https://auth0.com/docs/tokens/json-web-tokens/validate-json-...
> 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.
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.)
jwt.ifAuthentic(callback)
would be a good start. Callback can receive the decoded value and such.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?
It seems like people create short lived JWTs and then pass some opaque token to an auth endpoint to get a new JWT signed whenever the old one expires, or they store the JWTs in a database so that they can be revoked, making me question their usefulness.
To avoid the database lookup. Often you might want to hold some state, without the latency.
JWT is about your server being able to be stateless, whilst the client is stateful, which can speed up some... Irritating... Places of performance problems.
IMHO JWTs only make sense in some constrained contexts, such as:
1. You want a report, click on “generate”
2. The processing starts, you receive a token to access the resource
3. Once the file is created you get can access it by using the token previously received
In those kind of short term and limited use cases they can make things a bit nicer as the “report generation service” only need to check the token.
But in practice JWTs are often used used as a general authentication/authorization mechanism, and that makes little sense (and brings a lot of overhead).
Think about all the people/organisations that emit tokens you trust, or trust tokens you emit. Would they fit in an elevator? A meeting room? A conference venue?
If the code that mints all your JWTs and the code that verifies them are two methods in a class running in the same service and maintained by the same team, that's a sign you probably didn't need JWTs and an opaque token was more likely what you should use.
Alternatively, they have drank the microservice kool-aid and think that making a request to an AAA service every time the user wants to do something is just too much overhead (It isn't).
https://insomniasec.com/blog/auth0-jwt-validation-bypass https://auth0.com/blog/critical-vulnerabilities-in-json-web-...
You shouldn't use alg none unless you have some other way of protecting the contents of your JWT (like, say, network isolation) and you have verified the performance impact of signing a JWT is worth the possible security impact.
Not too many folks are in this situation, so in general, sign your JWTs!