JWT Attacks
Table of Contents
Guide 10 in Sarah’s Welcome to Web Security Series #
In this series, Sarah discusses some common vulnerability classes found in web security and how you can find and exploit them. Today’s focus is JWT attacks, a group of attacks that target weak, mishandled or poorly-configured JSON web tokens (‘JWT’).
Introduction #
JSON web tokens (also known as JWTs) are a secure way to transmit information between parties as a JSON object. Because of this, they are used in web security, notably for authorisation and access control. Therefore, weak JWTs, or ones that have been poorly configured, can create security vulnerabilities in web applications by allowing attackers to manipulate them and bypass other security mechanisms. The impact of JWT-based attacks largely depends on what the tokens were being used for.
Background on JWTs #
If you already know what JWTs are and how they are structured, you can skip this section.
One of the reasons why JWTs (in theory) can be trusted is because they can be verified with their digital signatures. JWTs are typically signed with a secret (using the HMAC algorithm) or with a key pair (using RSA or ECDSA). Signed tokens should not be confused with encrypted tokens (as JWTs can do both). Signed tokens verify the integrity of the information, that is to say, they guarantee that the information has not been modified in any way. If it has been altered then the signature will be different/wrong. On the other hand, encrypted tokens outright obfuscate and hide those claims. In terms of web security, both versions are used though the focus today will be on signed JWTs.
JWTs have a fixed structure: They have a header, a payload and a signature, each separated by a full stop. jwt.io is an excellent resource for viewing tokens in a clear, decoded manner (assuming you can decode it).1 Here is an example of a decoded token, where each part of the token has been highlighted for clarity:
The crucial part is the signature as it is the signature that guarantees the token’s integrity. Without knowing the signing key, it is (theoretically) not possible to generate the correct signature, unless it has been misconfigured. Observe how changing any part of the token yields a different signature:
But in this case, since we know the key, we can simply update the signature and the fictional receiving server will be able to process it. However, in the case of JWT attacks, an attacker is able to modify the token and correctly sign it, thus bypassing authentication and access controls. Imagine if the payload contained a section called “administrator” which was set to either true or false. If an attacker could change their token to read “true”, then sign it correctly, they could get administrator privileges.
Identifying Vulnerable JWT Systems #
Somewhat by design, JWTs can be flexible so that web developers can choose the implementation that suits their needs the best. However, this does lead to misconfiguration and vulnerabilities arising. The most common implementation flaw is having the signature being verified incorrectly, meaning the attacker can modify the token but not be detected by the application. So how can you tell if this is the case? Well, you have to look at how the token is being processed, particularly by studying the code. For example, developers sometimes use the functions verify()
and decode()
from the Node.js library jsonwebtoken
interchangeably, though the former is what should be used as the latter does not verify the signature of the token.
Another potential flaw is a server’s secret signing key not being, well, secret. In some other cases, the key can be brute-forced or guessed. If that key is leaked or brute-forced, then an attacker can generate valid signatures for any token, thus compromising the whole system.
Exploiting Vulnerable JWT Systems #
There are a number of ways to exploit JWT vulnerabilities, some of which involve manipulating certain headers or parameters. The possible exploits depend on what the JWT is actually being used for and what data is contained in its payload. Regardless of the system being targeted, the principle of any JWT attack is more or less the same:
- Access the desired JWT, either through an intercepted request, application storage, etc
- Decode and modify the JWT payload as desired
- Re-sign and submit
More complex attacks target the JWT’s header parameters, though the process is the same.
Defending Against JWT Attacks #
The short answer is simply to implement good processes for handling JWTs, with particular focus on the verification stage and the security of the private signing key. Using up-to-date libraries can help with this, as can robust signature verification processes. Moreover, whitelists can be implemented to protect the jku
header.2 It is also good practice to have a fixed expiration date (with a suitable revocation system) on JWTs and to avoid sending tokens in easily-modifiable URL parameters if possible.
Conclusion #
JWTs are used extensively for authentication and access control, so it is important to ensure they are being handled correctly to preserve their integrity. While the scope of the consequences of a successful JWT attack is often limited to a single user being compromised (given the scenarios in which they are commonly employed), if that user has particular privileges, it can lead to a wider system compromise. Therefore, developers should take care to ensure robust verification of incoming JWTs’ signatures as well as ensuring that the signing key cannot be leaked or bruteforced.
If you are interested in learning more about JWT attacks and web security, the WebSecurity Academy is a fantastic resource. You can create a free account and explore their labs here.