Learn Pentesting: A Deep Dive into JWT None Algorithm Vulnerability Testing
In this post, we’ll take an in-depth look at one of the classic JWT vulnerabilities – the misuse of the “none” algorithm – and demonstrate how to manually test for it during web-application penetration tests. This tutorial is intended for penetration testers and security professionals who want to understand both the theory and practical exploitation of JWT misconfigurations. We’ll cover the JWT structure, the nature of the vulnerability, and provide code examples and step-by-step instructions for manual testing.
Understanding JWT Basics
JSON Web Tokens (JWT) are an open standard (RFC 7519) used to securely transmit information between parties. A typical JWT consists of three parts:
- Header: Contains metadata about the token, including the signing algorithm (e.g., HS256, RS256) and the token type (JWT).
- Payload: Contains the claims – the pieces of information being transmitted (e.g., user details, roles).
- Signature: The cryptographic signature that verifies the authenticity of the token.
A JWT typically looks like this:
<base64url(header)>.<base64url(payload)>.<base64url(signature)>
For example, the header may look like this in JSON:
{
"alg": "HS256",
"typ": "JWT"
}
And the payload might be:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
The None Algorithm Vulnerability
What Is the None Algorithm?
The JWT specification allows for a special algorithm type, "none"
, which indicates that no digital signature or Message Authentication Code (MAC) is used. In a correctly implemented system, this option should either be disallowed or handled with extreme caution.
How the Vulnerability Arises
In some implementations, especially in older or misconfigured JWT libraries, the "none"
algorithm can be exploited to bypass signature verification. An attacker can craft a token where:
- The header’s
alg
field is set to"none"
. - The signature part is omitted (or an empty string).
If the application does not enforce a strict verification of the algorithm, it might accept the token without verifying its integrity. This allows the attacker to arbitrarily modify the payload, such as elevating privileges (e.g., changing "role": "user"
to "role": "admin"
).
Manual Testing Methodology
When manually testing for the JWT none algorithm vulnerability, the following steps are typically involved:
Capture a Legitimate JWT:
Identify and capture a valid JWT from the application. This can be done through intercepting traffic via a proxy like Burp Suite.Decode the JWT:
Use a JWT decoder (online tools or local scripts) to inspect the header and payload.Modify the Token:
- Change the header’s
alg
value to"none"
. - Optionally, modify the payload (e.g., set
"role": "admin"
). - Remove the signature part from the token.
- Change the header’s
Re-encode the Token:
Base64-encode the modified header and payload, then concatenate them with a trailing period to represent the empty signature.Send the Modified Token:
Replace the original token in your HTTP requests with the crafted token and observe the application’s response.Analyze the Outcome:
Look for changes in authorization, access to restricted areas, or other anomalous behaviors that indicate the application accepted the token without proper signature verification.
Crafting a JWT with the None Algorithm
Below is an example using Python to craft a JWT with the "none"
algorithm manually:
import base64
import json
def base64url_encode(data: bytes) -> str:
"""Encode bytes to base64url string without padding."""
return base64.urlsafe_b64encode(data).decode().rstrip("=")
# Define a header with 'none' algorithm and a typical payload.
header = {"alg": "none", "typ": "JWT"}
payload = {
"sub": "1234567890",
"name": "attacker",
"role": "admin", # escalate privileges if possible
"iat": 1516239022
}
# Convert header and payload to JSON, then base64url encode.
encoded_header = base64url_encode(json.dumps(header).encode())
encoded_payload = base64url_encode(json.dumps(payload).encode())
# Construct the token without a signature.
jwt_none_token = f"{encoded_header}.{encoded_payload}."
print("Crafted JWT with none algorithm:")
print(jwt_none_token)
Explanation
Base64url Encoding:
We define a helper function to perform base64url encoding while stripping padding (=
) characters.JSON Conversion:
The header and payload are converted to JSON strings, then encoded into bytes for base64url encoding.Token Structure:
The token is constructed asheader.payload.
(with the trailing dot representing an empty signature).
This script prints a crafted token that can be used in your testing.
Testing the Exploit with cURL
Once you have the crafted JWT, you can test it against a vulnerable endpoint. Suppose the endpoint is https://vulnerable-app.example.com/api/protected
and the JWT is normally passed in the Authorization
header. Here’s how you might use cURL to test it:
# Replace <crafted_token> with the output from the Python script.
curl -H "Authorization: Bearer <crafted_token>" https://vulnerable-app.example.com/api/protected
What to Look For
HTTP Status Codes:
A successful authentication (e.g., 200 OK) despite using an unsigned token may indicate a vulnerability.Behavioral Changes:
If you observe changes in the application behavior, such as access to admin features or unauthorized data, this is a strong indicator that the vulnerability exists.
Remediation and Best Practices
For Developers and Security Teams
Disable the None Algorithm:
Ensure that your JWT libraries or frameworks are configured to reject tokens with"alg": "none"
unless explicitly intended for non-production use.Enforce Algorithm Whitelisting:
Only allow a predetermined list of secure algorithms (e.g., HS256, RS256) during token verification.Regular Security Audits:
Continuously review and test JWT implementations as part of your secure development lifecycle.Library Updates:
Keep your JWT libraries up-to-date to mitigate known vulnerabilities.
For Penetration Testers
Document Findings:
Clearly document the steps taken and evidence of the vulnerability.Report Responsibly:
Provide remediation guidance alongside your report, highlighting the risks and recommended fixes.
Conclusion
The JWT none algorithm vulnerability is a classic example of how misconfigurations in token-based authentication can lead to severe security issues. By understanding the JWT structure and manually testing for the vulnerability, penetration testers can identify and help remediate potential security flaws in web applications.
We hope this detailed exploration serves as a valuable reference in your ongoing “Learn Pentesting” journey. Stay vigilant and keep testing!