Saltearse al contenido

Ataques a JWT

Un JWT transporta afirmaciones (claims) firmadas entre partes; se usa muchísimo para sesiones y autorización en APIs. Los fallos aparecen cuando la verificación de la firma es débil o incorrecta: entonces el atacante forja o altera el token y se convierte en otro usuario o en administrador.

Falsificación de identidad (cambiar sub/user), escalada de privilegios (poner role: admin), bypass de autenticación y persistencia si los tokens no caducan o no se revocan.

Tres partes en Base64URL separadas por puntos: header.payload.signature.

  • header: algoritmo (alg) y, a veces, kid, jku, x5u, jwk.
  • payload: claims (sub, role, exp, iss, aud…).
  • signature: HMAC (HS256) o firma asimétrica (RS256/ES256). La seguridad depende por completo de verificar bien la firma y el alg esperado.

Localiza JWTs (cookies, Authorization: Bearer, cuerpos), decodifica header y payload (Base64URL) e identifica alg, kid, jku y los claims que deciden el acceso.

# 1) alg=none (la app acepta tokens sin firma)
header: {"alg":"none","typ":"JWT"} -> payload alterado -> firma vacía
# 2) Confusión HS/RS (RS256 -> HS256)
# Si verifica HS256 usando la CLAVE PÚBLICA como secreto HMAC:
# firma el token con la clave pública RSA (que es pública) como secreto HS256.
# 3) Secreto HMAC débil (HS256) -> crackear offline
hashcat -m 16500 token.jwt wordlist.txt # 16500 = JWT
# crackeado el secreto -> firmas tokens arbitrarios
# 4) kid injection
# kid -> path traversal (apunta a /dev/null o a un fichero conocido) o SQLi
# 5) jku / x5u -> SSRF a tu JWKS
# apunta jku a tu servidor con tu clave pública -> firmas con tu privada
# 6) jwk header injection
# incrusta tu propia clave pública en el header y firma con tu privada

Verifica siempre si la app comprueba la firma (altera un claim sin tocar la firma; si te deja pasar, no la verifica) y si respeta exp.

jwt_tool (automatiza todos estos ataques), hashcat (secreto HMAC), jwt.io (decodificar/inspeccionar).

ATO, acceso admin, acceso a APIs de otros usuarios (combinado con IDOR), persistencia.

  • Tokens con alg: none, alg inesperado, o jku/x5u apuntando a dominios externos.
  • Picos de errores de verificación; tokens con exp en el pasado aceptados.

Logs del verificador/IdP, WAF/API gateway, y métricas de validación de tokens.

  1. Verificar SIEMPRE la firma y fijar el algoritmo esperado (lista blanca; no dejar que el token elija). Rechazar none.
  2. Secreto HMAC fuerte (aleatorio, largo) o claves asimétricas bien gestionadas.
  3. Validar iss, aud, exp, nbf; no confiar en kid/jku/x5u sin lista blanca de orígenes.
  4. Caducidad corta + refresh tokens revocables; no guardar secretos en el payload (va firmado, no cifrado: es legible).

Rotar la clave/secreto de firma (invalida todos los tokens), revisar accesos, y corregir la verificación.

  • Vulnerabilidad alg:none / confusión de algoritmo — numerosas librerías JWT (en varios lenguajes) la sufrieron hacia 2015 y han reaparecido en implementaciones posteriores; es el fallo histórico de JWT.
  • Secretos HMAC débiles por defecto en apps/plantillas → forja tras crackear.

CVEs concretos por librería en NVD (https://nvd.nist.gov/vuln/search) y GitHub Advisories (https://github.com/advisories).

  • ¿Se verifica la firma? (alterar claim sin tocar firma).
  • Probado alg:none y confusión HS/RS.
  • Intentado crackear el secreto HS256 (hashcat).
  • Probados kid, jku, x5u, jwk (inyección/SSRF).
  • Validación de exp/iss/aud comprobada.