What are JWTs?
A JSON Web Token (JWT), pronounced as “jwt,” serves as an open standard (RFC 7519) that outlines a concise and self-contained method for securely transmitting information in the form of a JSON object between different parties. It’s important to note that while all JWTs are tokens, not all tokens adhere to the JWT standard.
Due to its compact size, a JWT can be efficiently sent through various means such as a URL, a POST parameter, or within an HTTP header. This enables swift transmission. The information encompassed in a JWT includes all necessary details about an entity, eliminating the need for multiple database queries. Furthermore, the recipient of a JWT can validate the token without having to make additional server calls.
Format of a JWT
A JWT consists of 3 parts – a header, a payload, and a signature. These are separated by a dot, as shown below.
The header and payload parts of a JWT are just base64url-encoded JSON objects. The header contains metadata about the token itself, while the payload contains the actual “claims” about the user. Some of these claims have specific meaning, while others are left to be interpreted by the users. Common claims are:
- Issuer (iss)
- Subject (sub)
- Audience (aud)
- Expiration time (exp)
- Not before (nbf)
- Issued at (iat)
- JWT ID (jti)
To better visualize the construction of JWTs, consider experimenting on jwt.io.
As we can see, the data of a JWT token can easily be decrypted or tampered with by anyone with access to the token. Thus, every JWT token is secured with a cryptographic signature.
The signature is generated by the server by hashing the header and payload. It can be made even more secure by encrypting the hash. A change in even a single byte of the header or payload results in a different signature. A secret key is used to sign the token to ensure that no data within was modified. Unless the server’s secret signing key is known, it would be impossible to obtain the correct signature.
A JWT attack occurs when an attacker modifies JWTs before they are sent to the server. This is usually done to bypass authentication checks or access control mechanisms and gain access as an authenticated user.
Vulnerabilities which cause JWT attacks –
- Weak Key Generation: If the cryptographic key used to sign the JWT is weak or easily guessable, it becomes vulnerable to attacks like brute force or dictionary attacks.
- Insecure Transmission: When JWTs are transmitted over insecure channels without proper encryption, they can be intercepted and tampered with by attackers, leading to unauthorized access or information leakage.
- Insufficient Validation: Failure to properly validate the JWT’s integrity and authenticity on the server side can expose the system to token tampering and forgery. This includes not checking the token signature or trusting the token without verifying it thoroughly.
- Excessive Token Lifespan: Long-lived JWTs increase the window of opportunity for attackers. If a token’s expiration time is not appropriately set and regularly checked, it may remain valid for an extended period, increasing the risk of unauthorized access.
- Missing or Weak Session Management: If proper measures are not in place to manage and revoke JWTs, such as using token blacklisting or enforcing single-use tokens, an attacker with a stolen token could maintain access even after the legitimate user has logged out.
- Algorithm Vulnerabilities: The choice of the cryptographic algorithm used to sign the JWT is critical. Using deprecated or vulnerable algorithms can expose the system to cryptographic attacks, such as those exploiting weaknesses in the chosen algorithm.
Let’s understand some of these vulnerabilities through practical labs from PortSwigger.
We will be using Burp Suite Community for solving these labs. I would advice you to install the extension JWT Editor from the BApp Store in the Extensions section of Burp Suite. Also, referring the PortSwigger guide on Working with JWTs in Burp Suite will help you follow along better.
Lab 1: JWT Authentication Bypass via Unverified Signature
After launching the lab, log in using the credentials provided. The request is captured in Burp’s HTTP History:
The requests employing JWTs are highlighted in green. View the GET request for user wiener.
Our aim is to access the admin panel and delete the user carlos. On visiting the admin panel, we see the following:
It says we need to log in as the administrator to access this page. Let’s view the login request to understand the structure of the token. Under the “JSON Web Token” heading, we can view the decrypted token:
Let’s try to visit the admin panel again by changing the subject to “administrator” in that request.
We have successfully accessed the admin panel. Open this response in the browser by right-clicking and selecting “Show response in Browser”. Copy the URL and visit it in your browser. On clicking “carlos”, we again receive the unauthorized message. Go back to Burp and send the delete user request (/admin/delete?username=carlos) to repeater. Follow the same procedure of editing the token payload. After changing the subject of the payload and sending the request, user carlos is deleted successfully.
JWT libraries typically include a method for decoding tokens and one for verifying them. Take, for instance, the jsonwebtoken library in Node.js, which offers both verify() and decode(). At times, developers may mistakenly interchange these methods, only utilizing the decode() method for incoming tokens. This oversight essentially implies that the application neglects to verify the signature altogether.
Even though this lab uses JWT-based authentication, due to implementation flaws the server doesn’t verify the signature of any JWTs that it receives.
Lab 2: JWT authentication bypass via flawed signature verification
The goal is the same as the previous lab – to access the admin panel and delete the user carlos. Login using the given credentials and observe the request on Burp.
Now visit the “/admin” endpoint and observe the response.
Go to the “JSON Web Token” section and make the following changes before sending the request:
- Change the “alg” claim under the header section to none.
- Change the “sub” claim to administrator.
- Clear the Signature.
The request is sent successfully.
We have successfully accessed the admin panel. Open this response in the browser by right-clicking and selecting “Show response in Browser”. Copy the URL and visit it in your browser. On clicking “carlos”, we again receive the unauthorized message. Go back to Burp and send the delete user request (/admin/delete?username=carlos) to repeater. Follow the same procedure of editing the token payload. The user carlos will be deleted successfully.
JSON Web Tokens (JWTs) have the option of being signed through various algorithms or can remain unsigned. In instances where no signature is applied, the alg parameter is set to none, designating it as an “unsecured JWT.” Given the inherent risks associated with unsigned tokens, servers typically reject tokens lacking a signature. However, these filters can sometimes be bypassed using techniques like unexpected encodings and obfuscation.
The Impact of JWT Attacks
- Unauthorized Access: One of the most critical impacts is unauthorized access to protected resources. Attackers may forge or tamper with JWTs to gain access to functionalities or data that they are not supposed to have.
- Information Disclosure: If a JWT contains sensitive information in its payload, successful attacks can lead to the exposure of confidential data. This might include user credentials, personal details, or any other information embedded in the token.
- Session Hijacking: Successful attacks on JWTs can facilitate session hijacking, allowing attackers to take control of active user sessions and perform actions on behalf of the legitimate user.
- Elevation of Privilege: If an attacker can manipulate a JWT to increase their privileges, they may gain access to administrative functions or sensitive operations that were initially restricted.
Measures to Prevent JWT Attacks
- Validating JWTs Properly on the Server Side. Verify the signature to confirm the token’s integrity and authenticity. Also check claims like expiration time, issuer (iss), audience (aud), and issued at (iat).
- Utilize an active and up-to-date library for managing JWTs and ensure that your developers possess a thorough understanding of its functionality, including associated security considerations.
- Avoid Storing Sensitive Information in the JWT Payload.