Post

JSON Web Token (JWT) Security

JSON Web Token (JWT) Security

Introduction to JWT

JSON Web Tokens (JWTs) are an open standard (RFC 7519) for securely transmitting information between parties as a compact, self-contained JSON object. JWTs are commonly used for authentication and authorization in web applications, API security, single sign-on (SSO) implementations, and information exchange.

JWT Structure

A JWT consists of three parts separated by dots (.):

1
xxxxx.yyyyy.zzzzz
  1. Header - Contains metadata about the token type and signing algorithm
  2. Payload - Contains the claims (statements about an entity)
  3. Signature - Verifies the token hasn’t been altered

Example JWT

1
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Common JWT Security Vulnerabilities

1. Algorithm Vulnerabilities

None Algorithm Attack

1
2
3
4
5
6
7
8
9
10
11
// Original header
{
  "alg": "HS256",
  "typ": "JWT"
}

// Modified malicious header
{
  "alg": "none",
  "typ": "JWT"
}

The none algorithm indicates no signature verification is needed, potentially allowing attackers to forge tokens if accepted by the server.

Algorithm Confusion/Key Confusion Attack

1
2
3
4
5
6
7
8
9
10
11
// Original header (symmetric algorithm)
{
  "alg": "HS256",
  "typ": "JWT"
}

// Modified to asymmetric algorithm
{
  "alg": "RS256",
  "typ": "JWT"
}

This attack exploits implementations that don’t validate the algorithm. An attacker might switch from RS256 (asymmetric) to HS256 (symmetric) and use the public key as the HMAC secret.

2. Weak Secret Keys

Using weak, short, or predictable secrets for HMAC-based tokens enables brute force attacks:

1
2
# Example brute force attack using hashcat
hashcat -m 16500 -a 0 "JWT_TOKEN" wordlist.txt

3. Missing Signature Validation

Some implementations might:

  • Skip signature verification entirely
  • Check only that a signature exists without verifying it
  • Accept tokens with truncated signatures

4. Token Information Disclosure

JWTs store information in base64url-encoded format, not encrypted by default:

1
2
3
// Decoding a JWT payload (can be done by anyone)
const payload = atob(token.split('.')[1]);
console.log(JSON.parse(payload)); // All claims are visible

5. Token Replay Attacks

Without proper validation mechanisms, a token can be intercepted and reused:

1
2
// Captured valid token
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

6. Missing Expiration Time

Tokens without expiration remain valid indefinitely:

1
2
3
4
5
6
// JWT payload without expiration
{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

7. JWT Header Injection

1
2
3
4
5
6
7
// Maliciously constructed header
{
  "alg": "HS256",
  "typ": "JWT",
  "cty": "nested-jwt",
  "x5u": "http://attacker.com/key.pem"
}

Some implementations might fetch keys from the URL in x5u.

Best Practices for JWT Security

1. Proper Algorithm Selection and Validation

1
2
// Node.js example with explicit algorithm check
jwt.verify(token, secretKey, { algorithms: ['HS256'] });

2. Strong Secret Keys

1
2
# Generate a strong random key (32 bytes = 256 bits)
openssl rand -hex 32

3. Implement Token Expiration

1
2
3
4
5
6
7
// JWT payload with expiration
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022,
  "exp": 1516242622  // 1 hour after issued time
}

4. Use Additional Validation Claims

1
2
3
4
5
6
7
8
9
10
// Enhanced JWT payload
{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022,  // Issued at timestamp
  "exp": 1516242622,  // Expiration time
  "nbf": 1516239022,  // Not valid before
  "jti": "unique-token-id-123",  // Unique identifier
  "aud": "https://api.example.com"  // Intended audience
}

5. Token Revocation Mechanisms

Options include:

  • Token blacklisting in Redis/database
  • Short expiration times with refresh tokens
  • Version-based invalidation through user state

6. Secure Token Storage on Clients

1
2
// Storing JWT in httpOnly cookie (browser-side)
document.cookie = "token=your_jwt_token; HttpOnly; Secure; SameSite=Strict";

7. Protect Against XSS and CSRF

  • Use HttpOnly cookies to prevent JavaScript access
  • Implement proper CSRF protection
  • Validate token origin and audience

8. Consider Encrypted JWTs (JWE)

1
2
# Example using jose CLI tool
jose encrypt --input="jwt.txt" --recipient=public_key.pem > encrypted_jwt.txt

JWT Testing Checklist

  • Verify algorithm enforcement
  • Test for “none” algorithm acceptance
  • Check for algorithm confusion vulnerability
  • Attempt token replay
  • Verify expiration validation
  • Check signature validation
  • Test for header injection vulnerabilities
  • Verify claim validation (issuer, audience)
  • Test token revocation mechanism
  • Check for brute force vulnerability with weak keys

Tools for JWT Testing and Security

Analysis and Debugging

  • jwt.io: Online JWT decoder and debugger
  • jwtXploiter: Tool for testing JWT vulnerabilities

Attack Tools

  • jwt_tool: Python tool for JWT testing
    1
    
    python3 jwt_tool.py eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
    
  • Burp Suite JWT Extensions:
    • JWT Scanner
    • JSON Web Tokens
    • JSON Web Token Attacker

Library-specific Security

Node.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
const jwt = require('jsonwebtoken');

// Secure token creation
const token = jwt.sign(
  { sub: userId, role: 'user' },
  process.env.JWT_SECRET,
  { 
    algorithm: 'HS256',
    expiresIn: '1h',
    notBefore: '0s',
    audience: 'https://api.example.com',
    issuer: 'https://auth.example.com'
  }
);

// Secure verification
try {
  const decoded = jwt.verify(token, process.env.JWT_SECRET, { 
    algorithms: ['HS256'],
    audience: 'https://api.example.com',
    issuer: 'https://auth.example.com'
  });
} catch (err) {
  // Handle invalid tokens
}

Python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import jwt
from datetime import datetime, timedelta

# Secure token creation
payload = {
    'sub': user_id,
    'role': 'user',
    'iat': datetime.utcnow(),
    'exp': datetime.utcnow() + timedelta(hours=1),
    'aud': 'https://api.example.com',
    'iss': 'https://auth.example.com'
}

token = jwt.encode(payload, os.environ.get('JWT_SECRET'), algorithm='HS256')

# Secure verification
try:
    decoded = jwt.decode(
        token, 
        os.environ.get('JWT_SECRET'), 
        algorithms=['HS256'],
        audience='https://api.example.com',
        issuer='https://auth.example.com'
    )
except jwt.InvalidTokenError:
    # Handle invalid tokens

Real-world JWT Vulnerabilities

  1. CVE-2018-0114: Node.js node-jose library vulnerability allowed algorithm confusion attacks
  2. CVE-2020-28042: Ruby JWT gem bypassing signature verification with trailing data
  3. CVE-2022-21449: Java’s ECDSA signature validation vulnerability allowing crafted JWTs with blank signatures
  4. CVE-2022-29156: Spring Security accepting JWTs with invalid signatures due to parser issues

Common JWT Attack Scenarios

Scenario 1: Extracting Sensitive Information

1
2
3
1. Capture JWT from authorization header or cookies
2. Base64-decode the payload section
3. Extract sensitive information (emails, roles, permissions)

Scenario 2: Altering JWT Claims

1
2
3
4
5
1. Decode the existing JWT
2. Modify payload (e.g., change 'role': 'user' to 'role': 'admin')
3. Remove signature or attempt to bypass signature verification
4. Re-encode the tampered JWT
5. Use in authentication/authorization context

Scenario 3: Key Theft and Forgery

1
2
3
4
1. Identify JWT signing key location
2. Target vulnerabilities to extract the key (e.g., SSRF, path traversal)
3. Use the obtained key to forge valid tokens
4. Leverage forged tokens to access protected resources

Conclusion

JWT security requires a combination of:

  • Understanding common vulnerabilities
  • Implementing secure token handling practices
  • Using secure configuration of JWT libraries
  • Regular security testing of JWT implementations
  • Maintaining awareness of new vulnerabilities

By following these best practices and security measures, organizations can leverage the benefits of JWTs while minimizing the associated security risks.

This post is licensed under CC BY 4.0 by the author.