alltools.one
Security
2025-06-12
8 min
alltools.one Team
JWTSecurityAuthenticationAPIWeb Security

Seguridad de JSON Web Tokens: Vulnerabilidades Comunes y Soluciones

Los JWT son el estándar de facto para la autenticación de APIs, pero su aparente simplicidad oculta riesgos de seguridad reales. Los JWT mal configurados han provocado elusiones de autenticación, escalación de privilegios y filtraciones de datos. Esta guía cubre las vulnerabilidades más críticas y cómo prevenirlas.

Resumen de la Estructura JWT

Un JWT consta de tres partes codificadas en Base64URL separadas por puntos:

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMiLCJyb2xlIjoiYWRtaW4ifQ.signature
  • Header: Algoritmo y tipo de token
  • Payload: Claims (datos del usuario, expiración, etc.)
  • Signature: Verificación criptográfica

Inspecciona la estructura JWT con nuestro Codificador/Decodificador JWT.

Para una comprensión fundamental de la estructura JWT, consulta nuestra guía JWT Tokens Explicados.

Vulnerabilidades Críticas

1. Ataque de Confusión de Algoritmo

La vulnerabilidad JWT más peligrosa. Si un servidor acepta el header alg del token sin validación, un atacante puede:

Ataque: Cambiar el algoritmo de RS256 (asimétrico) a HS256 (simétrico) y firmar el token falsificado con la clave pública del servidor:

// Attacker's forged token
header: { "alg": "HS256", "typ": "JWT" }
payload: { "sub": "admin", "role": "superadmin" }
// Signed with the server's PUBLIC key as the HMAC secret

Si el servidor verifica tokens HS256 usando la clave pública como secreto, el token falsificado pasa la verificación.

Solución: Siempre especifica el algoritmo esperado explícitamente:

// WRONG - accepts whatever algorithm the token specifies
jwt.verify(token, key);

// CORRECT - enforce specific algorithm
jwt.verify(token, key, { algorithms: ['RS256'] });

2. Ataque de Algoritmo None

Algunas bibliotecas aceptan "alg": "none" — un token sin firma:

// Forged token with no signature
header: { "alg": "none", "typ": "JWT" }
payload: { "sub": "admin", "role": "superadmin" }
signature: ""  // empty

Solución: Nunca permitas el algoritmo none en producción. Lista explícitamente los algoritmos permitidos.

3. Secretos de Firma Débiles

Los JWT basados en HMAC (HS256/HS384/HS512) son tan fuertes como el secreto:

// TERRIBLE - can be brute-forced in seconds
secret = "password123"

// WEAK - dictionary attack vulnerable
secret = "my-jwt-secret"

// STRONG - 256+ bits of randomness
secret = "a3f2b8c9d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0"

Solución: Usa al menos 256 bits de aleatoriedad criptográfica para secretos HMAC. Mejor aún, usa claves asimétricas (RS256, ES256) donde la clave de firma nunca necesita ser compartida.

4. Expiración Faltante

Los tokens sin expiración nunca caducan — un token robado otorga acceso permanente:

// WRONG - no expiration
{ "sub": "user123", "role": "admin" }

// CORRECT - short expiration
{
  "sub": "user123",
  "role": "admin",
  "exp": 1705312800,
  "iat": 1705309200,
  "nbf": 1705309200
}

Mejor práctica: Los tokens de acceso expiran en 15-60 minutos. Usa refresh tokens (almacenados de forma segura) para sesiones largas.

5. Datos Sensibles en el Payload

Los payloads JWT están codificados en Base64URL, no cifrados. Cualquiera puede decodificarlos:

echo "eyJzdWIiOiIxMjMiLCJyb2xlIjoiYWRtaW4ifQ" | base64 -d
# {"sub":"123","role":"admin"}

Nunca incluyas: Contraseñas, claves API, números de tarjetas de crédito, datos personales (número de seguro social, registros médicos) ni ningún secreto en los payloads JWT.

6. Almacenamiento de Tokens (XSS vs CSRF)

AlmacenamientoVulnerable a XSSVulnerable a CSRF
localStorageNo
Cookie (sin flags)
Cookie HttpOnlyNo
Cookie HttpOnly + SameSiteNoNo

Recomendado: Almacena los JWT en cookies HttpOnly, Secure, SameSite=Strict. Esto previene el acceso desde JavaScript (defensa contra XSS) y las solicitudes entre sitios (defensa contra CSRF).

Set-Cookie: token=eyJ...; HttpOnly; Secure; SameSite=Strict; Path=/; Max-Age=3600

Lista de Verificación de Seguridad

  1. Especifica algoritmos explícitamente — nunca aceptes del header del token
  2. Rechaza el algoritmo none — siempre requiere una firma
  3. Usa secretos fuertes — 256+ bits para HMAC, 2048+ bits para RSA
  4. Establece expiración corta — 15-60 minutos para tokens de acceso
  5. Valida todos los claimsexp, iss, aud, nbf
  6. Almacena en cookies HttpOnly — no en localStorage
  7. Rota los secretos periódicamente — planifica la rotación de claves
  8. Nunca almacenes datos sensibles en el payload
  9. Usa claves asimétricas para sistemas distribuidos (RS256 o ES256)
  10. Implementa revocación de tokens — lista negra o expiración corta + refresh tokens

Firma Asimétrica vs Simétrica

AspectoHS256 (Simétrico)RS256 (Asimétrico)
ClaveSecreto compartidoPar de clave privada/pública
Quién puede firmarCualquiera con el secretoSolo el poseedor de la clave privada
Quién puede verificarCualquiera con el secretoCualquiera con la clave pública
Distribución de claveEl secreto debe compartirse de forma seguraSolo se comparte la clave pública
RendimientoMás rápidoMás lento
Ideal paraServicio únicoMicroservicios, sistemas distribuidos

Recomendación: Usa ES256 (ECDSA) para nuevas aplicaciones — proporciona seguridad asimétrica con rendimiento cercano a HMAC.

Estrategias de Revocación de Tokens

Los JWT son stateless por diseño — no hay forma integrada de revocarlos. Estrategias:

  1. Expiración corta: Si los tokens expiran en 15 minutos, la ventana de un token robado es limitada
  2. Rotación de refresh tokens: Emite un nuevo refresh token con cada uso; si un refresh token se usa dos veces, revoca todos los tokens
  3. Lista negra: Almacena los IDs de tokens revocados (claims jti) y verifica en cada solicitud
  4. Versionado de tokens: Incluye un número de versión en los claims; incrementa la versión del usuario al cerrar sesión

Preguntas Frecuentes

¿Debería usar JWT o cookies de sesión para autenticación?

Las cookies de sesión son más simples y más seguras para aplicaciones web tradicionales — el servidor controla el ciclo de vida de la sesión y la revocación es instantánea. Los JWT son mejores para APIs stateless, microservicios y aplicaciones móviles donde el almacenamiento de sesiones en el servidor es impráctico. Si eliges JWT, implementa las medidas de seguridad de esta guía.

¿Cuál es el tiempo de expiración ideal para JWT?

Para tokens de acceso: 15-60 minutos. Más corto es más seguro pero requiere renovación más frecuente. Para refresh tokens: 1-30 días, almacenados en cookies HttpOnly. Para tokens de un solo uso (verificación de correo, restablecimiento de contraseña): 1-24 horas.

Recursos Relacionados

Published on 2025-06-12
JSON Web Token Security: Common Vulnerabilities and Fixes | alltools.one