After reading the previous article, we know that JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
Although JWTs can be encrypted to also provide secrecy between parties, we will focus on signed tokens. Signed tokens can verify the integrity of the claims contained within it, while encrypted tokens hide those claims from other parties. When tokens are signed using public/private key pairs, the signature also certifies that only the party holding the private key is the one that signed it.
No matter how much we know about JWTs, a good question arises. If I get a JWT and I can decode the payload, how is that secure? I could just grab the token out of the header, decode and change the user information in the payload, and then send it back with the same correctly encoded secret, couldn’t I?
Well, JWTs aren’t concerned with encryption. They care about validation. That is to say, they can always find out whether the contents of a particular token have been manipulated. This means that user manipulation of the JWT is futile because the server will know and disregard the token. When issuing a token to the client, the server adds a signature based on the payload. Later, it verifies the payload and its matching signature.
The real question is, what is its motivation for not being concerned with encrypted contents?
JWTs can either be signed, encrypted, or both. If a token is signed but not encrypted, everyone can read its contents, but can’t change it without knowing the private key. Otherwise, the receiver will notice that the signature isn’t a match anymore.
Generally speaking, this is nice, but what happens if your entire JWT is stolen?
Because JWTs are used to identify the client, if one is stolen or compromised, the attacker has full access to the user’s account in the same way they would if the attacker had compromised the user’s username and password instead.
For instance, if an attacker gets hold of your JWT, they could start sending requests to the server identifying themselves as you and perform actions like making service changes, user account updates, etc. Once an attacker has your JWT, it’s game over.
However, there is one thing that makes a stolen JWT slightly better than a stolen username and password: timing. Because JWTs can be configured to automatically expire after a set amount of time – a minute, an hour, a day, etc. – attackers can only use your JWT to access the service until it expires.
In theory, that sounds great, right? One of the ways token authentication is said to make authentication more “secure” is via short-lived tokens. That’s one of the core reasons token-based authentication has really taken off in recent years: you can automatically expire tokens and mitigate the risk of relying on forever-cached “stateless” tokens.
In the security world, relying on cached data to make sensitive decisions like who can log into a service and what they can do is considered a bad thing. Because tokens are stateless and allow for some speed improvements over traditional session authentication, the only way in which they can remain somewhat “secure” is by limiting their lifespan, so they don’t cause too much harm when compromised.
The only problem here is that if an attacker was able to steal your token in the first place, they’re likely able to do it once you get a new token. The most common ways this happens is by man-in-the-middle (MITM) attacks on your connection or getting access to the client or server directly. And unfortunately, in these scenarios, even the shortest-lived JWTs won’t help you at all.
According to okta, tokens should be treated like passwords and protected as such. They should never be publicly shared and should be kept in secure data stores. For browser-based applications, this means never storing your tokens in HTML5 Local Storage and instead storing them in server-side cookies that are not accessible to JavaScript.
In general, token-based authentication does not provide any additional security over typical session-based authentication relying on opaque session identifiers. While there certainly is a good number of use cases for token-based authentication, knowing how the technology works and where your weak spots are is essential.
Another interesting thing to consider is that in some cases, a stolen JWT can actually be worse than a stolen username and password.
Let’s pretend, for a moment, that your username and password have been compromised. In this scenario, if the app you’re logging into is protected with multi-factor authentication, the attacker needs to bypass additional identity-proofing mechanisms in order to gain access to your account.
While guessing or brute-forcing a username and password is a very realistic scenario, being able to compromise a user’s multi-factor authentication setup can be quite difficult. Bypassing factors like app-based authorization, SMS verification, face ID or touch ID is significantly more challenging than guessing a user’s password.
Because of this, a compromised JWT can actually be a greater security risk than a compromised username and password. Imagine a scenario like the one above – where the app a user logs into is protected by multi-factor authentication. Once the user logs in and verifies themselves via multi-factor, they are assigned a JWT to prove who they are. If that JWT is stolen, the attacker no longer needs to bypass MFA directly like they would if they only had the user’s username and password – they can now directly make requests as the user without additional identity proofing. Quite a big risk.
Based on what we stated above, JWT stands as the authentication and user verification standard of today in web-based applications, but just like many other “new and cool things”, it has its own pros and cons:
Considering everything mentioned above, the real question is not whether you would use JWT, but when and how you should use it. As we said, for authorization and information exchange JWT is a solid standard, and it can be very reliable with additional security methods.
So, it is not a big surprise that JWT presently stands as a very popular standard you can use to trust requests by using signatures and exchange information between parties. Make sure you know when it’s best used when it’s best to use something else, and how to prevent the most basic security issues.