Dictionary Attack with Jwt Tokens
How Dictionary Attack Manifests in JWT Tokens
Dictionary attacks on JWT tokens exploit the predictable structure and validation process of JSON Web Tokens. Attackers leverage the fact that JWT tokens are often used for authentication without rate limiting or account lockout mechanisms. The attack typically unfolds in several stages:
import jwt
import time
from concurrent.futures import ThreadPoolExecutor
def brute_force_jwt(token, secret_candidates):
header, payload, signature = token.split('.')
for secret in secret_candidates:
try:
# Attempt to verify with candidate secret
jwt.decode(token, secret, algorithms=['HS256'])
return secret # Success - found the secret
except jwt.InvalidSignatureError:
continue
return None
# Common weak secrets attackers try
def common_secrets():
return [
'secret', 'password', '12345', 'admin', 'jwt', 'key',
'default', 'test', '123456', 'qwerty', 'abc123'
] + [f'secret{i}' for i in range(100)]
The vulnerability often stems from using weak signing secrets or exposing the signing key. When attackers obtain a JWT token (through interception, XSS, or other means), they can attempt to brute force the signing key. The attack becomes particularly effective when:
-
bsp;
- Weak or default secrets are used for token signing
- No rate limiting exists on token validation endpoints
- Attackers can parallelize requests across multiple IPs or distributed systems
- The application doesn't implement account lockout or exponential backoff
Another manifestation occurs through public key pinning attacks. If an application incorrectly trusts a JWT token's signature without proper key validation, attackers can substitute their own public keys. The attack pattern looks like:
# Malicious token creation
altered_payload = {"sub": "attacker", "admin": true}
malicious_token = jwt.encode(altered_payload, 'weak-secret', algorithm='HS256')
# If the server doesn't validate the secret properly, it accepts this token
Timing attacks represent a more sophisticated dictionary attack vector. By measuring response times when validating tokens with different secrets, attackers can infer information about the correct secret through timing differences in cryptographic operations.
JWT Tokens-Specific Detection
Detecting dictionary attacks on JWT tokens requires monitoring both the validation process and the token structure itself. Key detection methods include:
import re
from collections import Counter
def detect_weak_jwt_secrets(tokens):
weak_secrets = ['secret', 'password', '12345', 'admin', 'jwt']
detected = []
for token in tokens:
try:
header, payload, sig = token.split('.')
header_json = base64.urlsafe_b64decode(header + '==')
header_data = json.loads(header_json)
# Check for weak alg field
if header_data.get('alg') in ['none', '']:
detected.append({'token': token, 'issue': 'none algorithm detected'})
# Check for weak secrets in alg field
if header_data.get('alg') in weak_secrets:
detected.append({'token': token, 'issue': 'weak algorithm detected'})
except Exception:
continue
return detected
def monitor_jwt_validation(endpoint, threshold=100):
attempts = Counter()
def validate_and_count(token):
attempts[token] += 1
if attempts[token] > threshold:
return {'status': 'suspicious', 'count': attempts[token]}
return {'status': 'normal'}
return validate_and_count
middleBrick's JWT-specific scanning analyzes tokens for several vulnerability patterns:
| Check Type | What It Detects | Security Impact |
|---|---|---|
| Weak Secret Detection | Common weak signing secrets | Token forgery possible |
| Algorithm Confusion | none or weak alg values | Bypass signature validation |
| Public Key Substitution | Exposed or weak public keys | Token impersonation |
| Rate Limiting Absence | No validation throttling | Brute force feasible |
The scanner tests for algorithm confusion by attempting to decode tokens with various algorithm configurations, checking if the server accepts tokens with 'none' algorithm or mismatched signing methods. It also validates that public keys used for RS256 verification are properly secured and not exposed to attackers.
For continuous monitoring, middleBrick's Pro plan includes scheduled JWT security scans that test your endpoints against known weak secrets and algorithm confusion patterns, alerting you when vulnerabilities are detected before attackers can exploit them.
JWT Tokens-Specific Remediation
Remediating JWT dictionary attack vulnerabilities requires implementing proper token validation and security controls. Here are specific fixes for JWT implementations:
# Secure JWT validation middleware
def secure_jwt_validator(secret, max_attempts=5, lockout_duration=300):
from functools import wraps
import time
attempts = {}
lockouts = {}
def validate_token(token):
# Check for lockout
now = time.time()
if token in lockouts and now - lockouts[token] < lockout_duration:
raise Exception('Account temporarily locked')
# Validate signature with strong secret
try:
decoded = jwt.decode(token, secret, algorithms=['HS256'],
options={'verify_exp': True, 'verify_iat': True})
return decoded
except jwt.InvalidSignatureError:
# Increment attempt counter
attempts[token] = attempts.get(token, 0) + 1
if attempts[token] >= max_attempts:
lockouts[token] = now
attempts[token] = 0
raise
except jwt.ExpiredSignatureError:
raise Exception('Token expired')
return validate_token
# Secure token generation with strong secrets
import secrets
def generate_secure_jwt(payload, secret_length=32):
# Generate cryptographically strong secret
secret = secrets.token_urlsafe(secret_length)
# Set appropriate claims
payload['iat'] = int(time.time())
payload['exp'] = int(time.time()) + 3600 # 1 hour expiration
token = jwt.encode(payload, secret, algorithm='HS256')
return token, secret
# Algorithm confusion prevention
class SecureJWT:
def __init__(self, secret):
self.secret = secret
self.known_algorithms = ['HS256', 'RS256']
def decode_strict(self, token):
header = jwt.get_unverified_header(token)
if header.get('alg') not in self.known_algorithms:
raise ValueError('Unknown algorithm')
if header.get('alg') == 'none':
raise ValueError('None algorithm not allowed')
return jwt.decode(token, self.secret, algorithms=[header['alg']])
Additional remediation steps include:
-
bsp;
- Key Rotation: Implement automatic secret rotation every 30-90 days
- Short Expiration: Set JWT expiration to minutes rather than hours/days
- Refresh Token Pattern: Use short-lived access tokens with refresh tokens stored server-side
- IP Binding: Include client IP in token claims and validate on each request
- Secure Storage: Never store secrets in code or environment variables; use secret management services
For production deployments, integrate middleBrick's CLI tool into your CI/CD pipeline to automatically scan JWT endpoints before deployment:
# Scan JWT endpoints in CI/CD
middlebrick scan https://api.example.com/auth --output json --fail-below B
# GitHub Action example
- name: JWT Security Scan
uses: middlebrick/middlebrick-action@v1
with:
url: https://api.example.com/auth
threshold: B
output: json
This ensures that any dictionary attack vulnerabilities are caught early in the development lifecycle, preventing production security incidents.
Frequently Asked Questions
How can I tell if my JWT tokens are vulnerable to dictionary attacks?
Look for tokens with weak signing secrets (common words like 'secret', 'password', '12345'), tokens using the 'none' algorithm, or endpoints that don't implement rate limiting on token validation. middleBrick's scanner specifically tests for these patterns by attempting to decode tokens with common weak secrets and checking for algorithm confusion vulnerabilities. The scanner also verifies that your public keys are properly secured and not exposed to attackers.
What's the difference between JWT dictionary attacks and brute force password attacks?
Dictionary attacks on JWT tokens target the token's signing secret rather than user passwords. While brute force attacks guess user credentials, JWT dictionary attacks attempt to forge valid tokens by discovering the secret key used for signing. This is often more dangerous because if successful, the attacker gains the ability to create arbitrary valid tokens for any user, not just access one specific account. JWT attacks also bypass traditional account lockout mechanisms since they target the token validation process rather than authentication endpoints.