JSON Web Token (JWT) Security & Pitfalls: Algorithm confusion (alg: none), RS256 vs. HS256, and revocation.
JWT Internal Structure & Common Attacks
A JSON Web Token consists of three base64url-encoded parts separated by periods: Header.Payload.Signature. Because JWTs are stateless by design, common implementation flaws create devastating vulnerabilities.
+-----------------------+ +-----------------------+ +-----------------------+
| HEADER | . | PAYLOAD | . | SIGNATURE |
| {"alg": "RS256", ...} | | {"sub": "123", ...} | | HMAC / RSA signature |
+-----------------------+ +-----------------------+ +-----------------------+
1. The alg: "none" Vulnerability
Early JWT libraries allowed the header to declare {"alg": "none"}. Attackers stripped the signature and sent arbitrary payloads (e.g. {"role": "admin"}), which poorly implemented validators accepted without error.
Mitigation: Always explicitly whitelist the acceptable algorithm on the server:
jwt.verify(token, publicKey, { algorithms: ['RS256'] }); // Never allow 'none' or HS256!
2. Algorithm Confusion Attack (RS256 vs. HS256)
If a server expects RS256 (asymmetric; verifies with public key), an attacker can sign a forged token using HS256 (symmetric HMAC) using the server’s public key as the HMAC secret! If the backend blindly trusts the header algorithm, verification succeeds because the attacker used a known public key as the symmetric secret.
3. Real-Time Token Revocation (The JTI Bloom Filter Pattern)
Because JWTs cannot be revoked without maintaining server-side state, modern architectures include a unique token ID (jti) in the payload. When a user logs out or changes passwords, the jti is pushed to a Redis Bloom Filter or TTL set until its natural expiration. Validating the jti against Redis takes $< 1$ millisecond.