JSON Web Token (JWT) Security
Introduction
JSON Web Tokens (JWTs) are a cornerstone of modern API authentication, enabling secure, stateless session management across multiple interfaces (e.g., web, mobile). Their self-contained nature centralizes server-side logic, enhancing security by applying consistent protections. However, misconfigurations in JWT implementation can lead to severe vulnerabilities, such as session hijacking, privilege escalation, or data exposure. This guide provides a structured overview of JWT structure, common vulnerabilities with integrated testing steps, mitigation strategies, and tools for penetration testing.
CWE Mappings:
CWE-345: Insufficient Verification of Data Authenticity
CWE-347: Improper Verification of Cryptographic Signature
CWE-614: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute
JWT Fundamentals
JWT Structure
A JWT consists of three Base64Url-encoded components, separated by dots (.):
Header: Specifies the token type (
JWT) and signing algorithm (e.g.,HS256,RS256,none).Payload: Contains claims (e.g.,
username,admin,exp,aud) with session or user data.Signature: Ensures token authenticity using the algorithm specified in the header.
Example JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MH0.ko7EQiATQQzrQPwRO8ZTY37pQWGLPZWEvdWH0tVDNPUSigning Algorithms
None: No signature; claims cannot be verified.
Symmetric (e.g., HS256): Uses a single secret key for signing and verification.
Asymmetric (e.g., RS256): Uses a private key for signing and a public key for verification.
Token-Based Session Management
Unlike cookie-based systems, which rely on browser-managed cookies with attributes like Secure and HttpOnly, JWTs are managed client-side:
After authentication, the server issues a token in the response body.
Client-side JavaScript stores the token in
LocalStorageorSessionStorage.Tokens are sent in requests via the
Authorization: Bearer <token>header.
Benefits:
Ideal for decentralized applications (e.g., APIs serving web and mobile).
Resistant to CSRF since tokens are not auto-sent like cookies.
Drawbacks:
No built-in browser protections, vulnerable to XSS.
Requires explicit client-side handling, increasing complexity.
Example Client-Side Code:
API Setup for Testing
Endpoints:
http://<SERVER_IP>:<PORT>/api/v1.0/exampleX(replaceXwith example number).Methods:
POST: Authenticate to receive JWT with JSON body:
{"username":"user","password":"passwordX"}.GET: Verify user or escalate privileges with query:
?username=useror?username=admin.
Credentials:
username: user,password: passwordX(replaceXwith example number).
Example Commands:
Common JWT Vulnerabilities and Manual Testing
1. Sensitive Information Disclosure
Description: Sensitive data (e.g., passwords, internal IPs, flags) included in JWT claims, exposed client-side.
Impact: Attackers can decode payloads to access sensitive information.
Example Payload:
Development Mistake: Storing sensitive data in claims instead of server-side.
Manual Testing:
Authenticate to obtain a JWT.
Decode the payload to check for sensitive claims (e.g.,
password,flag).Alternatively, use JWT.io for decoding.
If sensitive data is present, the vulnerability is confirmed.
Fix: Store sensitive data server-side, use claims for non-sensitive data.
2. No Signature Verification
Description: Server skips signature validation, accepting forged tokens.
Impact: Attackers can modify claims (e.g.,
admin: 1) without validation.Development Mistake: Disabling signature verification.
Manual Testing:
Authenticate to get a JWT.
Remove the signature (keep the dot) and modify the payload to set
admin: 1.If the request succeeds, the server does not verify signatures.
Fix: Always verify signatures with the correct key.
3. Algorithm Downgrade to None
Description: Server accepts
nonealgorithm, bypassing signature checks.Impact: Attackers can set
alg: noneand forge arbitrary claims.Development Mistake: Allowing dynamic algorithm selection without restricting
none.Manual Testing:
Authenticate to get a JWT.
Modify the header to
{"alg":"none","typ":"JWT"}, encode in Base64Url (e.g., via CyberChef), and setadmin: 1in the payload.If accepted, the server allows
nonealgorithm.
Fix: Restrict allowed algorithms explicitly.
4. Weak Symmetric Secrets
Description: Weak secrets used for symmetric signing (e.g., HS256) are vulnerable to brute-forcing.
Impact: Attackers can crack secrets and forge valid signatures.
Development Mistake: Using predictable or short secrets (e.g.,
password123).Manual Testing:
Authenticate to obtain a JWT.
Save the JWT to a file and use Hashcat to crack the secret.
Forge a new token with the cracked secret and test.
Fix: Use long, random secrets.
5. Algorithm Confusion (Symmetric vs. Asymmetric)
Description: Server accepts both symmetric (HS256) and asymmetric (RS256) algorithms, using public key as symmetric secret.
Impact: Attackers can downgrade to HS256 and sign with known public key.
Development Mistake: Allowing mixed algorithms without validation.
Manual Testing:
Authenticate to get a JWT and public key.
Forge an HS256 token using the public key as the secret.
Test the forged token.
Note: May require patching Pyjwt (
algorithms.py, comment out lines 143-146 or adjust foris_ssh_keycondition).
Fix: Separate symmetric and asymmetric logic.
6. Excessive Token Lifetime
Description: Missing or overly long
expclaim results in persistent tokens.Impact: Stolen tokens remain valid indefinitely.
Development Mistake: Omitting
expclaim or setting long lifetimes.Manual Testing:
Use a provided token or authenticate to obtain one.
Check for
expclaim and test token validity over time.If the token remains valid after extended periods, the lifetime is excessive.
Fix: Set short
expvalues based on application needs.
7. Cross-Service Relay (Audience Misconfiguration)
Description: Unverified
audclaim allows tokens to be used across unintended applications.Impact: Privilege escalation across services (e.g., admin access on unintended app).
Development Mistake: Not enforcing
audclaim verification.Manual Testing:
Authenticate for appB (admin privileges).
Reuse appB token on appA to check for privilege escalation.
If appA accepts the token, audience verification is missing.
Fix: Enforce audience claim verification.
Impact on Penetration Testing
Implications for Pentesters
Forge Tokens: Bypass authentication or escalate privileges.
Exploit Weak Secrets: Crack secrets for session hijacking.
Extract Data: Access sensitive data from exposed claims.
Cross-Service Attacks: Exploit audience misconfigurations for unauthorized access.
Red Team Implications
Privilege Escalation: Forge tokens for silent admin access.
Persistent Access: Leverage long-lived tokens for extended attacks.
Data Exfiltration: Extract data from unverified JWTs.
Stealthy Attacks: Exploit insufficient logging for covert operations.
Mitigation Strategies
Strategy
Description
Example Code
Secure Payloads
Avoid sensitive claims; store data server-side.
python<br>payload = {"username": "user", "admin": 0}<br>flag = db_lookup(payload['username'], "flag")<br>
Enforce Signature Verification
Always validate signatures.
python<br>payload = jwt.decode(token, secret, algorithms="HS256")<br>
Restrict Algorithms
Explicitly define allowed algorithms.
python<br>payload = jwt.decode(token, secret, algorithms=["HS256", "HS384", "HS512"])<br>
Use Strong Secrets
Generate long, random secrets for symmetric signing.
python<br>secret = "random_32_char_string_1234567890abcdef"<br>
Separate Algorithm Logic
Differentiate symmetric and asymmetric validation.
python<br>header = jwt.get_unverified_header(token)<br>if "RS" in header['alg']:<br> payload = jwt.decode(token, public_key, algorithms=["RS256", "RS384", "RS512"])<br>elif "HS" in header['alg']:<br> payload = jwt.decode(token, secret, algorithms=["HS256", "HS384", "HS512"])<br>
Set Short Token Lifetimes
Include exp claim with short durations.
python<br>from datetime import datetime, timedelta<br>payload = {"username": "user", "admin": 0, "exp": datetime.now() + timedelta(minutes=5)}<br>
Enforce Audience Claims
Verify aud claim for specific applications.
python<br>payload = jwt.decode(token, secret, audience=["appA"], algorithms="HS256")<br>
Red Flags During Assessment
High Priority
Sensitive data in JWT claims (e.g., passwords, flags).
No signature verification or
nonealgorithm accepted.Weak symmetric secrets.
Algorithm confusion vulnerabilities.
Missing or excessive
expclaim.Unverified
audclaims.
Medium Priority
Long token lifetimes.
Insufficient logging of token usage.
Lack of token blocklisting.
Insecure token transmission (e.g., over HTTP).
Business Impact Analysis
Immediate Risks
Privilege Escalation: Forged tokens granting unauthorized access.
Data Exposure: Sensitive information leaked from claims.
Persistent Access: Long-lived tokens enabling prolonged attacks.
Cross-Service Attacks: Unauthorized access across applications.
Long-term Consequences
Reputational Damage: Breaches eroding user trust.
Regulatory Fines: Non-compliance with GDPR, PCI DSS, etc.
Incident Response Costs: Resources spent on recovery and mitigation.
Tools for Detection and Testing
Open Source
Burp Suite: Manipulate and test JWTs in requests.
CyberChef: Encode/decode JWT components with Base64Url.
Hashcat: Crack weak symmetric secrets.
John the Ripper: Alternative for secret cracking.
JWT.io: Decode and forge JWTs online.
OWASP ZAP: Automated scanning for JWT vulnerabilities.
Commercial
Netsparker: API and JWT vulnerability scanning.
Acunetix: JWT and session testing.
AppScan: Comprehensive security testing.
Qualys WAS: Cloud-based scanning.
Example Tool Usage
Practice Labs
Hack The Box: Challenges for JWT exploitation.
TryHackMe: API and JWT security rooms.
PortSwigger Web Security Academy: Labs focused on JWT vulnerabilities.
OverTheWire: Web exploitation wargames.
This reference is a penetration testing guide for JSON Web Token (JWT) security vulnerabilities. Misconfigured JWTs enable attackers to forge tokens, escalate privileges, or expose sensitive data. Secure payload management, strict signature verification, strong secrets, short lifetimes, and audience enforcement are critical for mitigation.
Last updated