JWT Security: The Invisible Flaws In Your Authentication Fortress
JWTs grant access to sensitive resources; a misconfiguration here could compromise millions.
How JWT Works and Where Things Go Wrong
JWTs (JSON Web Tokens) encode claims (e.g., `username`, `roles`) in three parts: header (algorithm and token type), payload (data), and signature (HMAC/RSA).
Common Mistakes
- Weak algorithms: Defaulting to HS256 (hashed signatures) instead of RS256 (asymmetric keys).
- Missing token expiration: No `exp` header or infinite expiry.
- Insecure key storage: Hardcoding secrets in client-side code or logs.
- Improper validation: Omitting signature checks or accepting unverified tokens.
Real-World Exploits: Plausible Scenarios
In 2021, a fintech startup leaked 10M user tokens due to a Redis cache storing JWTs in plaintext.
Example 1: Algorithm Vulnerability
A company using JWTs with `none` algorithm (no signature) allowed attackers to forge tokens for admin access.Example 2: Expiration Bypass
A healthcare app ignored the `exp` claim, letting stolen tokens grant perpetual access to patient records.Step-by-Step Exploitation Demonstration
const jwt = require('jsonwebtoken');
// Vulnerable setup: hardcoded, weak algorithm, no expiration
const secret = 'weak123';
const token = jwt.sign({ username: 'admin', role: 'admin' }, secret, { algorithm: 'HS256', expiresIn: 'never' });
console.log(token);
# Brute-force the HMAC key (if algorithm is known)
$ jwt crack --alg HS256 --token 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...' --key-word-list /usr/share/wordlists/rockyou.txt
# Or decode without signature (if auth is not enabled)
$ jwt decode -a none -t 'eyJhbGciOiJlbmhvcGltOlIxNzUiLCJhbGciOiJIUzI1NiJ9...'
Mitigations You Should Be Implementing
1. Enforce Strong Algorithms
// Use RS256 with a secure key pair (e.g., OpenSSL-generated private key)
const secret = fs.readFileSync('private.pem');
const token = jwt.sign({ // payload }, secret, { algorithm: 'RS256' });
2. Validate Token Expiry & Claims
from datetime import datetime, timedelta
# Generate tokens with expiration
payload = {
"exp": datetime.utcnow() + timedelta(hours=1),
"iat": datetime.utcnow()
}
token = jwt.encode(payload, secret, algorithm="RS256")
3. Secure Key Management
Never commit secrets to version control. Use environment variables or Google Key Management Service (KMS).
# Store keys in Vault
$ vault kv put jwt/cert/private @ private.pem
# Inject at runtime
export JWT_SECRET=$(vault kv get -field=private jwt/cert/private)
4. Implement Token Revocation
Use Redis to track revoked tokens:# Maintain a blacklist
revoked_tokens = redis.Redis()
revoked_tokens.sadd("revoked_jwt", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...")
# Check before validation
if token in revoked_tokens.smembers("revoked_jwt"):
raise AuthenticationError("Token revoked")
Tools & Further Reading
- OWASP JWT Cheat Sheet: Scan here
- JWTTools: Burp Suite plugin for token analysis
- CVE-2022-0806: Critical vulnerability in Firebase Authentication's JWT handling
Key Takeaways
- Mandate RS256/ES256 over HS256.
- Always validate `exp` and `iat` claims.
- Blacklist compromised tokens.
- Rotate secrets regularly.