JWT Attack Lab

JSON Web Token Exploitation

Back to Vault

Educational Purpose Only

JWT attacks can compromise authentication systems. This lab teaches recognition and defense of JWT vulnerabilities. Only test on systems you own or have explicit permission to assess.

Understanding JWT Structure

JSON Web Tokens consist of three Base64URL-encoded parts separated by dots:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiam9obiIsInJvbGUiOiJ1c2VyIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
   └────────── Header ──────────┘.└─────────────── Payload ───────────────────────────────────┘.└────────── Signature ──────────┘

1. Header

Contains the token type and signing algorithm:

{
  "alg": "HS256",  // Signing algorithm
  "typ": "JWT"     // Token type
}

2. Payload (Claims)

Contains the actual data - user info, permissions, expiration:

{
  "sub": "1234567890",    // Subject (user ID)
  "name": "John Doe",     // Custom claim
  "role": "user",         // Authorization level
  "iat": 1516239022,      // Issued at timestamp
  "exp": 1516242622       // Expiration timestamp
}

3. Signature

Ensures token integrity - created using the header, payload, and secret:

HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)

JWT Decoder & Attack Simulator

Paste a JWT token to decode it, or modify the payload to simulate attacks:

HEADER
-
-
PAYLOAD
-
-
SIGNATURE
-
Cannot decode - binary data

Common JWT Attacks

1. Algorithm "none" Attack

Some libraries accept tokens with "alg": "none", allowing unsigned tokens:

// Original header
{"alg": "HS256", "typ": "JWT"}

// Malicious header
{"alg": "none", "typ": "JWT"}

// The token now has NO signature requirement!
// Just modify the payload and leave signature empty

2. Algorithm Confusion (RS256 → HS256)

If server expects RS256 (asymmetric) but accepts HS256 (symmetric):

// Server's public key (meant for verification only)
// Attacker uses it as HMAC secret

// Original: RS256 with private key signature
// Attack: HS256 signed with PUBLIC key as secret

// If server uses public key for both algorithms,
// attacker can forge valid signatures!

3. Weak Secret Brute Force

If the secret is weak (like "secret", "password", etc.):

# Using jwt-cracker or hashcat
hashcat -a 0 -m 16500 jwt.txt wordlist.txt

# Common weak secrets:
# secret, password, 123456, jwt_secret, key

4. Claim Manipulation

Modifying claims without proper signature verification:

// Original payload
{"user": "john", "role": "user", "id": 1001}

// Modified payload (privilege escalation)
{"user": "john", "role": "admin", "id": 1}

5. Token Replay

Using stolen tokens before expiration, or if no expiration is set:

// Token without expiry - valid forever!
{"user": "john", "role": "user"}

// Proper token with expiry
{"user": "john", "role": "user", "exp": 1703566400}

JWT Forge (Payload Editor)

Modify claims and generate a new (unsigned) token to understand the attack:


Defense Mechanisms

1. Always Verify Signatures

// Python example with PyJWT
import jwt

try:
    # ALWAYS specify the expected algorithm!
    decoded = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
except jwt.InvalidSignatureError:
    return "Invalid signature"
except jwt.ExpiredSignatureError:
    return "Token expired"

2. Reject "alg": "none"

// Explicitly whitelist allowed algorithms
const options = {
    algorithms: ['HS256', 'RS256'],  // Only these!
    // Never include 'none'
};
jwt.verify(token, secret, options);

3. Use Strong Secrets

# Generate a cryptographically secure secret
import secrets
SECRET_KEY = secrets.token_hex(32)  # 256 bits

# Or use RS256 with proper key pair

4. Implement Proper Expiration

{
  "sub": "user123",
  "iat": 1703480000,        // Issued at
  "exp": 1703483600,        // Expires in 1 hour
  "nbf": 1703480000         // Not valid before
}

5. Token Revocation (Blacklist/Whitelist)

# Maintain a blacklist of revoked tokens (by jti claim)
revoked_tokens = redis.get("revoked_tokens")

if token.jti in revoked_tokens:
    return "Token has been revoked"

Knowledge Check

1. What makes the "alg: none" attack possible?

A) Libraries that accept unsigned tokens when algorithm is "none"
B) Weak encryption algorithms
C) Missing HTTPS
D) Short token length

2. How does the RS256 to HS256 confusion attack work?

A) By cracking the RSA private key
B) Using the public key as the HMAC secret
C) By downgrading to weaker encryption
D) By intercepting the token in transit

3. What is the BEST defense against JWT attacks?

A) Using longer tokens
B) Encrypting the entire token
C) Explicitly whitelisting allowed algorithms and verifying signatures
D) Storing tokens in cookies only