Seguridad en JWT: vulnerabilidades, ataques y buenas prácticas
Los JSON Web Tokens (JWT) se han impuesto como estándar de facto de la autenticación sin estado en las aplicaciones web modernas. Esa misma flexibilidad es la que produce errores de configuración con consecuencias graves. Cuando un pentester ve un JWT no ve un identificador de sesión: ve una superficie de ataque criptográfica.
Lo esencial en un minuto
- Un JWT está codificado, no cifrado: cualquiera que tenga el token lee todos los claims del payload.
- La algorithm confusion (de RS256 a HS256) y el algoritmo
nonesiguen siendo los fallos de firma de mayor impacto que encontramos en implementaciones propias y en aplicaciones heredadas. - Un secreto HS256 es una contraseña. Un token interceptado se rompe fuera de línea con Hashcat, sin volver a tocar el sistema objetivo.
- Los parámetros de cabecera que aporta el cliente, como
kidyjku, convierten la verificación de la firma en una superficie de inyección. - Una firma válida no dice nada sobre la validez de los claims:
exp,issyaudhay que comprobarlos en cada petición. - Los access tokens, en memoria; los refresh tokens, en cookies
HttpOnly,Secure,SameSite. Nunca enlocalStorage.
Anatomía de un JWT: cabecera, payload y firma
Un JWT tiene tres partes —una cabecera (header), un payload y una firma— separadas por un punto (.). Interceptado, parece una cadena larga de caracteres aleatorios. Este es un ejemplo real:
eyJraWQiOiI5MTM2ZGRiMy1jYjBhLTRhMTktYTA3ZS1lYWRmNWE0NGM4YjUiLCJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsImV4cCI6MTY0ODAzNzE2NCwibmFtZSI6IkNhcmxvcyBNb250b3lhIiwic3ViIjoiY2FybG9zIiwicm9sZSI6ImJsb2dfYXV0aG9yIiwiZW1haWwiOiJjYXJsb3NAY2FybG9zLW1vbnRveWEubmV0IiwiaWF0IjoxNTE2MjM5MDIyfQ.SYZBPIBg2CRjXAJ8vCER0LA_ENjII1JakvNQoP-Hw6GG1zfl4JyngsZReIfqRvIAEi5L4HV0q7_9qGhQZvy9ZdxEJbwTxRs_6Lb-fZTDpW6lKYNdMyjw45_alSCZ1fypsMWz_2mTpQzil0lOtps5Ei_z7mM7M8gCwe_AGpI53JxduQOaB5HkT5gVrv9cKu9CsW5MS6ZbqYXpGyOG5ehoxqm8DL5tFYaW3lB50ELxi0KsuTKEbD0t5BCl0aCR2MBJWAbN-xeLwEenaqBiwPVvKixYleeDQiBEIylFdNNIMviKRgXiYuAvMziVPbwSgkZVHeEdF5MQP1Oe2Spac-6IfA
La cabecera y el payload son simples objetos JSON codificados en Base64Url. Codificados, no cifrados: quien acceda al token puede descodificarlos y leerlos sin ninguna clave.
Visualizar la estructura de un JWT
Un JWT —técnicamente un JWS, es decir, un JSON Web Token «firmado»— se compone de tres secciones separadas por puntos: Header.Payload.Signature.
{ "alg": "HS256", "typ": "JWT" }{ "sub": "andrej", "role": "hacker" }HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
"secret"
) = MmM0ZGMxM2Y1NWQ2YTY2YTELa cabecera
La cabecera guarda los metadatos del propio token: sobre todo su tipo y el algoritmo criptográfico que lo protege. Descodificar la primera parte del token anterior da esto:
{
"kid": "9136ddb3-cb0a-4a19-a07e-eadf5a44c8b5",
"alg": "RS256"
}
El payload
El payload contiene los claims: las afirmaciones que el token hace sobre quien lo presenta. Es el objetivo principal de la manipulación durante un proyecto. La sección central de nuestro ejemplo, descodificada:
{
"iss": "portswigger",
"exp": 1648037164,
"name": "Andrej Šebeň",
"sub": "andrej",
"role": "pentester",
"email": "andrej@haxoris.com",
"iat": 1516239022
}
La firma
Como la cabecera y el payload se leen y se modifican sin ninguna dificultad, la seguridad de cualquier mecanismo basado en JWT descansa entera sobre la firma criptográfica.
El servidor que emite el token calcula un hash de la cabecera y del payload codificados en Base64Url con una clave de firma secreta. El mecanismo garantiza dos cosas:
- Como la firma deriva directamente del resto del token, cambiar un solo byte de la cabecera o del payload produce una firma que ya no encaja.
- Sin conocer la clave de firma del servidor no debería ser posible generar la firma correcta de una cabecera o un payload falsificados.
Qué busca un atacante en un JWT
Los JWT son legibles por diseño, así que un atacante los trata como fuente de reconocimiento y no como datos cifrados. Desde el lado ofensivo, es en el payload donde suelen alojarse los fallos de lógica. Estos son los claims que revisamos de entrada:
| Claim | Para qué sirve | Qué comprobamos |
|---|---|---|
iss (Issuer) | Identifica quién emitió el token. | ¿Lo valida de verdad el backend? Un sistema que acepta tokens emitidos por un tercero no autorizado queda expuesto a una confusión de emisor. |
sub (Subject) | El usuario o la entidad que el token representa, casi siempre un identificador. | Referencia directa insegura a objetos (IDOR). ¿Podemos cambiarlo por admin o por user_id=1 y saltarnos la autorización? |
aud (Audience) | Identifica al destinatario previsto. | ¿Se puede reutilizar contra otro microservicio, mucho más privilegiado, un token emitido para uno distinto? |
exp (Expiration Time) | La marca de tiempo Unix en la que caduca el token. | ¿La aplica el servidor? Encontramos API que aceptan tokens caducados indefinidamente con una regularidad incómoda. |
nbf (Not Before) | El momento antes del cual el token no debe aceptarse. | Falta por completo de la lógica de validación en la mayoría de los casos. |
iat (Issued At) | Cuándo se creó el token. | Útil para calcular vidas útiles y detectar tokens que no rotan nunca. |
Reconocimiento del payload: la mina de información
El payload es visible para cualquiera que tenga el token, de modo que el equipo de desarrollo debería tratarlo como información pública. En nuestros proyectos aparecen con frecuencia detalles internos expuestos sin ninguna necesidad en claims personalizados:
- Cartografía de la red interna: claims como
"node_ip": "10.0.4.12","cluster": "prod-eu-west-1a"o"db_host": "internal-db.local"revelan la arquitectura interna y los rangos de direcciones. - Fugas sobre la pila tecnológica: las convenciones de nombres delatan la tecnología de base. Un claim como
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameseñala un backend Microsoft .NET / Entra ID y nos permite apuntar a vulnerabilidades propias de esa pila. - Datos personales: exposición innecesaria de correos, teléfonos, nombres completos o direcciones postales. Aquí no hablamos de estilo. El art. 5.1.c) del RGPD impone la minimización de datos y el art. 32 exige medidas adecuadas al riesgo; un payload hablador se analiza bajo ese artículo 32, es decir, como medida de seguridad insuficiente, y no como un detalle de implementación. Es el mismo razonamiento con el que la AEPD valora una exposición de datos por un defecto técnico.
- Enumeración de tenants y de roles: claims como
"tenant_id": "uuid","is_god_mode": falseo"permissions": ["read:profile"]exponen el esquema de autorización y nos dan los nombres exactos de los parámetros a los que apuntar para escalar privilegios.
Un ejemplo de payload demasiado hablador, capturado en un entorno real:
{
"iss": "auth.internal-corp.local",
"sub": "usr_99812",
"email": "andrej@haxoris.com",
"role": "admin",
"internal_ip": "10.240.12.88",
"db_shard": "shard-04-eu",
"is_admin": true,
"exp": 1748037164
}
Bearer tokens y refresh tokens: arquitectura y almacenamiento
Una implementación sólida de JWT descansa sobre dos tipos de token: access tokens (bearer tokens) de vida corta y refresh tokens de vida larga. Guardarlos mal es, con diferencia, el hallazgo que más se repite en nuestros informes.
Bearer tokens (access tokens)
- Autorizan las llamadas a la API y son deliberadamente de vida corta, normalmente entre 5 y 15 minutos.
- Guárdalos solo en memoria de la aplicación. Evita
localStorageysessionStorage: cualquier XSS explotada los deja al alcance del atacante.
Refresh tokens
- Existen únicamente para obtener nuevos access tokens cuando el anterior caduca.
- Van en cookies
HttpOnly,Secure,SameSite, que impiden su lectura desde JavaScript, reducen mucho el robo de token por XSS y ayudan además a contener el CSRF.
El manual del pentester: ataques habituales contra JWT
En un pentesting de aplicaciones web recorremos siempre los vectores siguientes.
A. Fallos de verificación de la firma
Muchas vulnerabilidades de JWT nacen de una verificación de firma defectuosa, no de criptografía rota. Históricamente, algunas bibliotecas aceptaban el algoritmo none, lo que permitía suprimir la firma por completo y modificar a voluntad claims como el rol del usuario. Hoy todas las bibliotecas de referencia rechazan none por defecto, pero el fallo reaparece en aplicaciones heredadas y en implementaciones escritas a medida: en cuanto te topas con una pila no estándar, conviene probarlo.
Otro clásico es la algorithm confusion. Es una de las vulnerabilidades de JWT con más impacto y merece entenderse con precisión.
- RS256 es asimétrico. El servidor firma los tokens con su clave privada y los verifica con la clave pública correspondiente. Esa clave pública suele estar libremente disponible, expuesta por ejemplo en un endpoint
/.well-known/jwks.json. - HS256 es simétrico. El servidor usa un único secreto compartido para firmar y para verificar.
El ataque explota lo que ocurre cuando un servidor acepta ambos algoritmos sin fijar explícitamente cuál espera:
- El atacante obtiene la clave pública del servidor, muchas veces de forma trivial, desde el endpoint JWKS.
- Modifica el payload: por ejemplo, eleva
"role": "user"a"role": "admin". - Cambia en la cabecera
"alg": "RS256"por"alg": "HS256". - Vuelve a firmar el token modificado entero (cabecera y payload) usando la clave pública como secreto HS256.
- El servidor recibe el token, lee
alg: HS256y lo verifica con la clave pública en el papel de secreto HMAC. Encaja, y el token falsificado se acepta.

La causa de raíz no es una criptografía rota: es un servidor que confía a ciegas en la cabecera alg que aporta el cliente para decidir cómo verificar el token. En condiciones normales, tocar alg invalidaría la firma, porque la firma cubre a la vez cabecera y payload. Pero el atacante vuelve a firmar el token modificado completo, así que la nueva firma es perfectamente válida bajo el algoritmo sustituido.
Las bibliotecas recientes han eliminado en gran medida estos fallos. Siguen apareciendo, eso sí, en aplicaciones heredadas y en implementaciones de JWT hechas en casa.
B. Secretos de firma débiles
Una aplicación que usa un algoritmo simétrico como HS256 es exactamente tan segura como el secreto con el que firma.
Durante un test de intrusión, un JWT interceptado se ataca íntegramente fuera de línea con herramientas como Hashcat o John the Ripper. Los secretos débiles —el nombre de la empresa, palabras de diccionario, frases previsibles— caen a menudo en cuestión de minutos, y a partir de ahí se pueden emitir tokens válidos para cualquier usuario sin volver a interactuar con la aplicación objetivo.
C. Inyección en parámetros de cabecera
La cabecera de un JWT admite parámetros opcionales como kid (Key ID) y jku (JWK Set URL), que ayudan al servidor a determinar qué clave debe usar al verificar. Como esos valores los aporta el cliente, confiar en ellos sin validarlos abre vulnerabilidades serias.
Los vectores más frecuentes:
- manipular el parámetro
jkupara que apunte a un endpoint JWKS controlado por el atacante; - explotar un salto de directorio a través del parámetro
kidcuando las claves se cargan directamente del sistema de ficheros; - abusar de una inyección SQL cuando el valor de
kidse concatena en una consulta a base de datos.
Las bibliotecas de JWT maduras resuelven bien estos casos. La lógica de verificación escrita a medida sigue generando hallazgos proyecto tras proyecto.
D. Fallos de validación de claims
Una firma válida no convierte automáticamente un token en fiable. Cada claim relevante para la seguridad tiene que validarse también en la aplicación.
En nuestros proyectos aparecen con regularidad API que:
- aceptan tokens caducados porque ignoran el claim
exp; - no validan el destinatario previsto (
aud), lo que permite reutilizar en un servicio un token emitido para otro; - dan por bueno cualquier valor de emisor (
iss); - se apoyan solo en claims que controla el cliente —
role,tenant,permissions— sin comprobar la autorización en el servidor.
Estos fallos de lógica suelen tener más impacto real que las debilidades criptográficas, porque permiten usar tokens legítimos para fines que nadie previó.
Herramientas para probar la seguridad de los JWT
Descodificar Base64 y manipular firmas a mano no es eficiente. Para automatizar estos ataques hay herramientas especializadas:
- JWTAuditor: una plataforma de pruebas que se ejecuta en el cliente, pensada para pentesting. Permite inspección rápida, detección automatizada de vulnerabilidades (algoritmo
none, inyecciones de cabecera) y rotura fuera de línea, sin exponer los tokens del cliente a la telemetría de un tercero. - Burp Suite (extensión JWT Editor): muy utilizada en pruebas dinámicas para manipular tokens al vuelo durante la interceptación HTTP.
- JWT.io: mantenida por Auth0, es la herramienta de referencia para descodificar un token a mano y comprobar deprisa su estructura y su firma en la fase de reconocimiento.
- JWTLens: una alternativa ligera y cuidadosa con la privacidad. Descodifica y verifica los tokens enteramente en el navegador con la API Web Crypto nativa, así que tus tokens y tus claves no salen de tu ordenador. Como no emite ninguna petición de red durante la verificación, sirve bien para validar algoritmos y firmas sin riesgo de fuga.
Buenas prácticas defensivas
Para que tus tokens no acaben entre los hallazgos críticos del próximo informe, estos son los controles que hay que aplicar:
- Fija el algoritmo esperado: no dejes nunca que el token entrante decida cómo se le va a verificar. Configura la rutina de validación para un algoritmo concreto (por ejemplo
RS256) y rechazanonesin condiciones. - Valida todos los claims: una firma válida solo demuestra que nadie ha alterado el token, no que siga siendo válido para el usuario actual. Comprueba explícitamente
exp(caducidad),iss(emisor) yaud(destinatario) en cada petición. - Trata los secretos simétricos como contraseñas: si tu arquitectura obliga a firmar en simétrico (
HS256), esa clave equivale a una contraseña de administración. Al menos 256 bits de entropía, generada con un generador criptográficamente seguro y guardada en variables de entorno o en un gestor de secretos. Nunca escrita en el código fuente. Si tus sistemas están en el ámbito del Esquema Nacional de Seguridad, la guía CCN-STIC-807, sobre criptología de empleo en el ENS, es la referencia pública con la que se justifican algoritmos y longitudes de clave ante la entidad auditora. - Recuerda que codificar no es cifrar: no pongas datos sensibles, datos personales ni contraseñas dentro del payload de un JWT. Quien intercepte el token lo descodifica al instante.
- Aísla el almacenamiento de los tokens: nunca guardes un access token de vida corta en
localStorageni ensessionStorage, donde basta una XSS para exfiltrarlo. Los access tokens, estrictamente en memoria del cliente; los refresh tokens de vida larga, en cookiesHttpOnly,Secure,SameSite.
Endurecimiento avanzado: el patrón phantom token
En los entornos más sensibles, la defensa más eficaz contra el robo en el lado del cliente consiste en no exponer nunca el JWT al frontend. Las arquitecturas empresariales recientes implementan a menudo el patrón «phantom token»:
- El servidor de autorización entrega a la aplicación cliente una cadena de sesión opaca y aleatoria, en lugar de un JWT.
- Cuando el cliente llama a la API, envía esa cadena opaca.
- La pasarela de API intercepta la petición, valida el token opaco contra el servidor de autenticación (o contra el almacén de sesiones) y lo canjea por un JWT firmado y completo.
- La pasarela reenvía ese JWT a los microservicios internos.
Preguntas frecuentes sobre la seguridad de los JWT
01¿Un JWT está cifrado?
No. La cabecera y el payload de un JWT firmado estándar (un JWS) solo están codificados en Base64Url, no cifrados. Cualquiera que tenga el token puede descodificar y leer todos sus claims. La firma protege la integridad, no la confidencialidad: ni los datos sensibles ni los datos personales tienen sitio en el payload de un JWT.
02¿Qué es la algorithm confusion en un JWT?
La algorithm confusion aparece cuando el servidor deja que la cabecera alg del propio token decida cómo se verifica la firma. El atacante recupera la clave pública RSA del servidor, sustituye RS256 por HS256 en la cabecera, modifica el payload y vuelve a firmar el token entero usando esa clave pública como secreto HMAC. Un servidor que acepta los dos algoritmos da por buena la falsificación. La defensa consiste en fijar en el servidor el algoritmo esperado.
03¿Dónde se guardan los access tokens y los refresh tokens en un navegador?
Los access tokens de vida corta, solo en memoria de la aplicación. Los refresh tokens de vida larga, en cookies HttpOnly, Secure y SameSite, para que JavaScript no pueda leerlos. Ni unos ni otros deben ir a localStorage ni a sessionStorage, donde basta una única vulnerabilidad XSS para exfiltrarlos.
04¿Cómo se rompe un secreto de firma HS256?
Un token HS256 interceptado se ataca íntegramente fuera de línea, con herramientas como Hashcat o John the Ripper y sin ninguna interacción adicional con la aplicación objetivo. Los secretos débiles —el nombre de la empresa, palabras de diccionario, frases previsibles— caen a menudo en minutos, y a partir de ahí se pueden emitir tokens válidos para cualquier usuario. Un secreto simétrico necesita al menos 256 bits de entropía procedentes de un generador criptográficamente seguro.
05¿Basta una firma válida para confiar en un JWT?
No. Una firma válida solo demuestra que el token no ha sido alterado. La aplicación todavía tiene que validar cada claim relevante para la seguridad: exp para la caducidad, iss para el emisor y aud para el destinatario previsto. Y no debe apoyarse nunca en claims que aporta el cliente, como role o permissions, sin comprobar la autorización en el servidor.
06¿Qué exige el RGPD sobre los datos personales que viajan en un token?
El art. 5.1.c) del RGPD impone la minimización de datos y el art. 32 exige medidas de seguridad adecuadas al riesgo. Un payload que transporta correos, teléfonos o identificadores internos sin necesidad incumple lo primero y se analiza bajo lo segundo, porque el token viaja legible para cualquiera que lo intercepte. El art. 32.1.d) añade «un proceso de verificación, evaluación y valoración regulares de la eficacia» de esas medidas, que es exactamente lo que documenta el informe de un test de intrusión.
Cómo puede ayudarte Haxoris
La seguridad de los tokens rara vez se rompe por la criptografía: se rompe por la configuración. Te ayudamos a encontrar esas desviaciones antes de que dé con ellas un atacante:
- Pentesting de aplicaciones web y API, con atención específica a los flujos de autenticación y de autorización.
- Revisión de la lógica de emisión y de verificación de JWT, incluidas la gestión de claves, el tratamiento del JWKS y la rotación, dentro de una auditoría de ciberseguridad o de una revisión de código fuente.
- Evaluación fuera de línea de la robustez de tus secretos de firma simétricos.
- Revisión de diseño del almacenamiento de tokens, de las duraciones de sesión y de la arquitectura de refresh tokens.
Las pruebas de aplicación se apoyan en la guía de pruebas OWASP WSTG y en los requisitos de gestión de sesiones del OWASP ASVS, que cubren directamente lo que describe este artículo. El retest va incluido, sin coste adicional, para comprobar las correcciones. Todos nuestros test de intrusión se ejecutan con encargo escrito y con un alcance definido en contrato: en España, el acceso no autorizado a un sistema de información se castiga por el art. 197 bis del Código Penal, y el borrado o el daño de datos ajenos por el art. 264. Lo que separa un pentest de un delito es exactamente esa autorización previa, y por eso empieza el trabajo por ahí. El informe fechado que entregamos sirve además de evidencia del «proceso de verificación, evaluación y valoración regulares» que exige el art. 32.1.d) del RGPD.
Haxoris es un proveedor europeo, una empresa establecida en la Unión Europea con oficinas en Bratislava y Praga. Tus tokens de ejemplo, tus capturas y tu informe se quedan en la Unión: sin transferencias internacionales del capítulo V del RGPD y sin cláusulas contractuales tipo, porque el RGPD se nos aplica directamente.
Conclusión
Los JWT no son inseguros por diseño. Se vuelven inseguros en el momento en que una aplicación deja que el token decida cómo hay que validarlo, o en que confunde una firma válida con una autorización. Fija el algoritmo, valida cada claim, trata los secretos como contraseñas de administración y mantén los tokens fuera del almacenamiento del navegador: la mayoría de los hallazgos que describe este artículo desaparecerán de tu próximo informe de pentesting.
Fuentes y lecturas recomendadas
Las metodologías y los detalles técnicos de este artículo se apoyan en las referencias siguientes:
- PortSwigger Web Security Academy. JWT Security Vulnerabilities. Un desglose detallado de los fallos de verificación de firma y de las inyecciones de cabecera. portswigger.net/web-security/jwt
- InfoSec Writeups. JWT Pentesting: A Journey from Token to Takeover. Casos prácticos de explotación de configuraciones de token. infosecwriteups.com
- Auth0 / JWT.io. Introduction to JSON Web Tokens. La documentación de referencia sobre la estructura de los tokens y la RFC 7519. jwt.io/introduction
- JWTAuditor. Security Testing Tool. Utilizada para la manipulación de payloads y la detección automatizada de vulnerabilidades. jwtauditor.com
- Reglamento (UE) 2016/679 (RGPD). Art. 5.1.c), minimización de datos; art. 32, seguridad del tratamiento; art. 32.1.d), proceso de verificación, evaluación y valoración regulares.
- CCN-STIC-807. Criptología de empleo en el Esquema Nacional de Seguridad. Guía pública de la serie CCN-STIC del Centro Criptológico Nacional, referencia habitual en España para elegir y justificar algoritmos y longitudes de clave.
Última verificación: 12 de septiembre de 2026.