Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Use JWT the Right Way (stormpath.com)
31 points by 0xmohit on June 15, 2016 | hide | past | favorite | 17 comments


This is a pretty low bar on JWT advice.

Here are some more:

* Make sure that you use JSON.parse to handle incoming JWT bodies if you are writing custom JS code. Using any eval() derivative function opens up XSS

* If you include any strings from a user into the body of your JWT, for example as part of a claim, you must output encode and input validate that data to make sure the result is a valid JSON object in which only the claim expected was modified (think of inputs such as "my address', exp:'never', username: 'admin").

* Your server side code must actually check the claims inside your JWTs. This is really an awfully common thing not to do.

* If using access tokens (or other such tokens), know that there are two tokens, an id_token and an access_token. Endpoints may expect both, so that they can use the id_token to obtain a principle and access_token for credentials. It is important that the server code checks that these tokens belong together (at_hash for access_tokens, st_hash for security_tokens). Otherwise the theft of a user id_token implies a malicious user can auth with it even if their access_token is for a different user.

* Look for open redirects in your JWT-application, fiercely enforce CORS, etc policies. Know that session fixation attacks plague OpenID Connect, OAuth, etc.


Always happy to get feedback. Again, this article was written back in 2014, and will be updated.

In regards to your advice about id_tokens and access_tokens. Usually, what I've seen in most attacks is that if a malicious user can get one, they can get both.

A lot of your points though are valid outside of using JWTs. Open redirects vulnerabilities should be plugged and sanitizing user input should be looked at regardless of what you are using in a web application.


Agreed everywhere.

Users tend to be looser with their id_tokens (for example posting on forums, stackexchange, etc) than with access_tokens because they understand the access_tokens are credentials whereas the id_tokens are (technically) not.

Definitely open redirects and the session fixation problems are not JWTs specifically - it's just that they tend to plague applications that use JWTs for transport. I admit it's kind of like telling people that talking on the phone while driving is a bad way to use your seatbelt. It's true - but maybe not scoped enough.


> These tokens are usually signed to protect against manipulation (not encrypted) so the data in the claims can be easily decoded and read

Is this really true? I mean, if you can decode the token you must have access to the secret anyway?

From https://github.com/auth0/node-jsonwebtoken

    var token = jwt.sign({ foo: 'bar' }, 'shhhhh');
    var decoded = jwt.verify(token, 'shhhhh');
    console.log(decoded.foo) // bar


Encoding != encryption. This article isn't discussing JWE (JSON Web Encryption), but rather JWS (JSON Web Signature).

These tokens are base64-encoded and signed. They can be decoded easily, but not forged or altered without knowledge of the secret key.


Read a little further in the README.

  var token = jwt.sign({ foo: 'bar' }, 'shhhhh');
  var decoded = jwt.verify(token, 'shhhhh');
  console.log(decoded.foo) // bar
  var decoded_unverified = jwt.decode(token); // NOTE: no secret!
  console.log(decoded_unverified.foo) // bar


If you have a secret in the JWT you definitely want to encrypt it (JWE instead of JWS).

But yes, it's true. A signature will protect against manipulation though, like the article points out, which is enough for a lot of applications.


You can decode the token without the secret. Generally JWT is not encrypted and you shouldn't put sensitive info inside. But you can't modify the token without knowing the secret, because you won't have a valid signature.

So I can hand out session tokens, and you can't modify the user ID or the expiration time unless you know the secret.


Just to be a little bit pedantic about the article.

    Do not contain any sensitive data in a JWT.
If there's nothing sensitive in the JWT then why might we encrypt it? Sometimes the whole purpose of a JWT is to pass some sensitive auth information whether as a session cookie or an authentication token that a service uses.

    If you worried about replay attacks, include a nonce (jti claim), expiration time (exp claim), and creation time (iat claim) in the claims
This isn't always the case... One of the reasons JWT is so powerful is the asymmetric key operations built in to the spec. If some JWT generation and signing body signs a JWT and someone else steals the JWT, all consumer services of the signing service are vulnerable to a replay attack. The JWT is valid for use at ALL consumer services.

If you have symmetric keys and are encrypting/signing a JWT to communicate, and you want to prevent replay attacks with a JTI and EXP, you've lost the stateless property of JWT in order to do it correctly, and you haven't solved the problem of using the JWTs at OTHER services. It only works for 1 to 1 communication.

If you're preventing replay attacks inside of a JWT you've chose the wrong battle and you've decided to design a cryptographic protocol on top of JWTs. Don't pick this fight. Just go home.

    The secret signing key should only be accessible by the issuer and the consumer
This won't be the case for asymmetric keys. Services that create JWTs and sign them for other services to verify should not share the private key with other services. This is basic crypto but if someone reads this ONLY this article they may not know.


OP is most likely using "JWT" to refer to a JWS - the most common form of JWT by a very wide margin.

JWSes are not encrypted, only signed, so it is true that you must not put sensitive information inside a JWS.

You might want to use a JWE, but that is not in scope for the article.


Thanks, Evan. these are all good points, I'm surprised to see this on HN since it is an old article I wrote.

In regards to the replay attacks, if you are using JWTs in a 3 party setup, and they are validating JWTs locally (not sending them back to a validation endpoint), the jti claim won't be enough.

Thanks again for clearing that up! Considering this blog post may still have a use, I'll update it soon.


Heheheh, no problem. I recognized it was your article, Tom. Sorry to be pedantic. Jose is really just way too complicated. Go Dukes!


Definitely not pedantic! Believe it or not, JOSE was still a draft when this blog post was released into the wild.


What would you need in addition to a jti claim in a 3 party setup with local validation?


I love the idea of JWT but I don't understand how you would use them to store a lot of information, as the token it self would balloon in size. For example using a JWT to authenticate an API request. The JWT would store a user ID and a list of permissions. What if a user has 100 permissions? The token is going to get huge....? Unless I'm completely misunderstanding how to use them.


JWT should not be looked at as a session replacement. For example, you cannot invalidate a JWT token before it's TTL. If you really wanted, you'd need to manage a blacklist of tokens on the server and compare every token against that list which would defeat the purpose of JWT's scalability benefits.

You can, however, come up with other strategies like switching up 100 permissions for 10 permission groups and similar ground-up designs which are JWT-friendly.


> If you really wanted, you'd need to manage a blacklist of tokens on the server and compare every token against that list which would defeat the purpose of JWT's scalability benefits.

The blacklist approach does presumably incur network latency, however, the amount of overhead/space for the blacklist is going to be substantially smaller than the total set of JWTs.

Also: the blacklist only needs to be maintained until a blacklisted token naturally expires, further enabling performance.

Any number of stores or structures would be suitable for the maintaining the blacklist: Memcached, Redis, even a bloom filter (especially if tokens aren't regularly blacklisted) will suffice.

Granted, there are tradeoffs, and at this point, traditional sessions probably make more sense, but it s at least possible.

It's much easier to scale recall from a (likely) small blacklist of token IDs + TTLs than all sessions, everywhere.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: