Conceptos

JWT (JSON Web Tokens) - Autenticacion basada en tokens

#appsec#auth#defense#web

Los JWT (JSON Web Tokens) son tokens autocontenidos para transmitir informacion de sesion de forma estandarizada. Se usan en autenticacion basada en tokens, muy comun en APIs, y su…

Definicion

Los JWT (JSON Web Tokens) son tokens autocontenidos para transmitir informacion de sesion de forma estandarizada. Se usan en autenticacion basada en tokens, muy comun en APIs, y su seguridad depende de como se firman, validan y expiran.

Contexto

  • Se apoya en gestion de sesiones: Gestion de sesiones (Session Management).
  • Relacionado con fallos de autenticacion: Authentication Failures (OWASP Top 10 2025 - A07).
  • Relevante para APIs: OWASP API Security Top 10 (2019).
  • OAuth usa tokens de acceso; ver OAuth 2.0 y 2.1 (OAuth Security).

Desarrollo (MIT-style)

1) Autenticacion basada en tokens (API context)

Con el auge de las API, la autenticacion basada en cookies no siempre encaja bien (multi‑cliente: web + mobile). Por eso se usa token-based session management:

  • El servidor entrega un token tras autenticacion.
  • El cliente lo guarda (p. ej., LocalStorage).
  • En cada request, el cliente adjunta el token en Authorization: Bearer.

Documentacion de API (cuando existe):

  • Postman (proyectos)
  • Swagger/OpenAPI (spec)

2) Estructura de un JWT

Un JWT tiene 3 partes codificadas en Base64Url y separadas por puntos:

  1. Header: tipo (JWT) y algoritmo.
  2. Payload: claims (registrados + publicos/privados).
  3. Signature: asegura autenticidad.

Algoritmos de firma clave:

  • None: sin firma (riesgoso si se acepta).
  • HS256 (simetrico): secreto compartido.
  • RS256 (asimetrico): clave privada firma, clave publica verifica.

Nota: JWT puede cifrarse (JWE), pero su fuerza principal es la firma.

3) API de laboratorio (estructura comun)

  • Endpoint base: http://MACHINE_IP/api/v1.0/exampleX.
  • POST: autenticacion y obtencion de JWT.
  • GET: verificacion/consulta de usuario.

Credenciales base:

  • username: user
  • password: passwordX

cURL autenticacion:

Terminal window
curl -H 'Content-Type: application/json' -X POST -d '{ "username" : "user", "password" : "passwordX" }' http://MACHINE_IP/api/v1.0/exampleX

cURL verificacion:

Terminal window
curl -H 'Authorization: Bearer [JWT token]' http://MACHINE_IP/api/v1.0/example2?username=Y

4) Vulnerabilidades comunes y ejemplos

A) Divulgacion de informacion en claims

Problema: se incluyen datos sensibles dentro del JWT (p. ej., password, hash, flag, IP interna).

Ejemplo vulnerable:

payload = {
"username" : username,
"password" : password,
"admin" : 0,
"flag" : "[redacted]"
}
access_token = jwt.encode(payload, self.secret, algorithm="HS256")

Solucion: guardar datos sensibles en backend y consultar con username.

payload = jwt.decode(token, self.secret, algorithms="HS256")
username = payload['username']
flag = self.db_lookup(username, "flag")

B) No verificar firma

Problema: el servidor acepta tokens sin firma valida.

Ejemplo vulnerable:

payload = jwt.decode(token, options={'verify_signature': False})

Solucion: siempre verificar firma con secreto o clave publica.

payload = jwt.decode(token, self.secret, algorithms="HS256")

C) Downgrade a None

Problema: aceptar alg = None en header.

Ejemplo vulnerable:

header = jwt.get_unverified_header(token)
signature_algorithm = header['alg']
payload = jwt.decode(token, self.secret, algorithms=signature_algorithm)

Solucion: limitar algoritmos permitidos con lista fija.

payload = jwt.decode(token, self.secret, algorithms=["HS256", "HS384", "HS512"])

D) Secretos simetricos debiles (HS256)

Problema: secreto corto o predecible permite cracking offline.

Ejemplo practico (solo laboratorio):

Terminal window
# guardar token en jwt.txt
# descargar lista comun
wget https://raw.githubusercontent.com/wallarm/jwt-secrets/master/jwt.secrets.list
# crackear secreto
hashcat -m 16500 -a 0 jwt.txt jwt.secrets.list

Alternativas: John the Ripper.

Solucion: usar secreto largo y aleatorio.


E) Confusion de algoritmos (RS256 -> HS256)

Problema: mezclar algoritmos simetricos y asimetricos.

Ejemplo vulnerable:

payload = jwt.decode(token, self.secret, algorithms=["HS256", "HS384", "HS512", "RS256", "RS384", "RS512"])

Ataque: usar clave publica (conocida) como secreto en HS256.

Ejemplo (forjar token):

import jwt
public_key = "ADD_KEY_HERE"
payload = {
'username' : 'user',
'admin' : 0
}
access_token = jwt.encode(payload, public_key, algorithm="HS256")
print(access_token)

Nota de laboratorio: en PyJWT puede requerir editar jwt/algorithms.py (lineas 143-146 y 258) para reproducir el bug en entornos vulnerables. Alternativa: usar jwt.io.

Solucion: separar algoritmos y validar segun tipo.

header = jwt.get_unverified_header(token)
algorithm = header['alg']
payload = ""
if "RS" in algorithm:
payload = jwt.decode(token, self.public_key, algorithms=["RS256", "RS384", "RS512"])
elif "HS" in algorithm:
payload = jwt.decode(token, self.secret, algorithms=["HS256", "HS384", "HS512"])

5) Vida util del token (exp)

Problema: JWT sin exp o con vida demasiado larga.

Ejemplo vulnerable: token sin expiracion.

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXIiLCJhZG1pbiI6MX0.ko7EQiATQQzrQPwRO8ZTY37pQWGLPZWEvdWH0tVDNPU

Solucion: incluir exp razonable.

lifetime = datetime.datetime.now() + datetime.timedelta(minutes=5)
payload = {
'username' : username,
'admin' : 0,
'exp' : lifetime
}
access_token = jwt.encode(payload, self.secret, algorithm="HS256")

Nota: tokens de actualizacion pueden mitigar sesiones largas.


6) Ataque de retransmision entre servicios (audience)

Problema: no validar aud en cada aplicacion.

Escenario: token emitido para appB aceptado en appA y hereda permisos.

Solucion: validar audiencia al decodificar:

payload = jwt.decode(token, self.secret, audience=["appA"], algorithms="HS256")

7) Resumen de defensas

  • No incluir datos sensibles en claims.
  • Verificar firma siempre.
  • Bloquear alg = None.
  • No mezclar algoritmos HS/RS sin logica estricta.
  • Usar secretos fuertes (HS) o claves correctas (RS).
  • Definir exp y caducidad acorde a riesgo.
  • Validar aud en cada servicio.

No se cubre aqui la suplantacion de JWKS; ver room: hammer.

Ejemplos

Decode JWT (manual o jwt.io).

Authorization header:

Authorization: Bearer <jwt>

Pitfalls / Errores comunes

  • Guardar passwords/hashes en claims.
  • Aceptar tokens sin firma valida.
  • Secretos debiles reutilizados.
  • Tokens sin expiracion o demasiado largos.
  • No verificar aud en arquitecturas multi‑app.

Diagrama

flowchart LR
A[Login] --> B[JWT firmado]
B --> C[Cliente guarda token]
C --> D[Authorization: Bearer]
D --> E[API valida firma + exp + aud]

Referencias

  1. RFC 7519 (JWT): https://tools.ietf.org/html/rfc7519
  2. jwt.io: https://jwt.io/
  3. CyberChef: https://gchq.github.io/CyberChef/
  4. PyJWT docs: https://pyjwt.readthedocs.io/en/stable/
  5. Hashcat: https://hashcat.net/hashcat/
  6. John the Ripper: https://www.openwall.com/john/
  7. JWT secrets list (Wallarm): https://raw.githubusercontent.com/wallarm/jwt-secrets/master/jwt.secrets.list
  8. Postman: https://www.postman.com/
  9. Swagger: https://swagger.io/
  10. THM Intro to Web Hacking: https://tryhackme.com/module/intro-to-web-hacking
  11. THM Enumeration & Brute Force: https://tryhackme.com/r/room/enumerationbruteforce
  12. THM Session Management: https://tryhackme.com/r/room/sessionmanagement
  13. THM Hammer (JWKS): https://tryhackme.com/r/room/hammer