Volver al glosario

JWT

8 min de lectura

Un JWT, o JSON Web Token, es un formato compacto definido en el RFC 7519 para transportar afirmaciones entre partes, firmado como JWS o cifrado como JWE. Es un formato de token, no un sistema de sesiones: quien lo recibe tiene que validar algoritmo, emisor y audiencia, y un token en vigor no se puede revocar sin un estado que el formato no tiene.

24 de julio de 2026
Compartir:

Cómo funciona

Un JWT son tres segmentos en base64url separados por puntos: una cabecera, una carga de afirmaciones y una firma, o bien una estructura cifrada. Cualquiera que tenga el token puede leer la carga, porque base64url es una codificación y no un cifrado. Eso es lo primero que hay que dejar claro con un cliente que cree que el token protege los datos que lleva dentro. Un JWT firmado protege la integridad, no la confidencialidad. Solo la forma cifrada, JWE, esconde el contenido.

La cabecera nombra el algoritmo. La carga lleva afirmaciones registradas como emisor, sujeto, audiencia y caducidad, más lo que añada la aplicación. La firma cubre los dos primeros segmentos, así que cualquier cambio en las afirmaciones la invalida, siempre que quien recibe compruebe.

Su atractivo es que mueve el estado al cliente. Un servicio puede aceptar una petición, verificar una firma con una clave que ya tiene, leer la identidad del usuario y los ámbitos de la carga, y contestar sin preguntarle nada a nadie. Eso es de verdad útil cuando se cruzan fronteras entre servicios. El coste es que el token es válido porque lo dice él y porque las matemáticas cuadran, no porque un servidor lo haya consultado. Todo lo que sale mal con los JWT viene de ese intercambio.

El RFC 7519 permite además un JWT no asegurado, con el algoritmo puesto a none y la firma vacía. Eso es una parte legítima de la especificación para casos en los que el transporte ya es de confianza, y es la razón de que «JWT» y «firmado» no sean sinónimos.

Qué sale mal

Casi todos los hallazgos de JWT que escribimos son una validación que quien recibe no hizo, y el motivo es que el token llega con aspecto de autoridad.

El primero es fiarse de la cabecera. Si quien recibe lee el algoritmo del token y después lo usa, el algoritmo lo elige el atacante. Ponlo a none y, en una librería que lo respete, la firma no se comprueba. Ponlo a HS256 en un servicio que espera RS256 y algunas librerías verificarán el HMAC usando la clave pública RSA como secreto compartido, y esa clave es pública por definición. Los dos casos son antiguos, los dos están arreglados en las librerías actuales, y los dos siguen apareciendo en servicios que congelaron una versión de librería hace años o que escribieron su propia verificación.

El segundo es un secreto débil. Un token HS256 es un objetivo de crackeo sin conexión: cogemos un token válido de nuestra propia sesión y lo pasamos contra un diccionario en local, sin hacerle ni una petición al servicio. Los secretos que eligió una persona, o que se copiaron del tutorial de un framework, caen. Una vez recuperado el secreto fabricamos tokens para cualquier usuario con las afirmaciones que queramos, y en el servidor no hay nada que los distinga.

El tercero es la afirmación que nadie comprueba. Un token emitido por otro tenant del mismo proveedor de identidad, para otra audiencia, es perfectamente válido y está firmado con una clave en la que el servicio confía. Saltarse las comprobaciones de audiencia y de emisor convierte un token válido de otro sitio en un token válido aquí. En parques multi-tenant este es el hallazgo que más importa y el que menos probablemente aparezca en el informe de un escáner.

El cuarto no es una vulnerabilidad, sino un hecho de operación que acaba siéndolo: un JWT no se puede revocar. Un usuario cierra sesión, se deshabilita una cuenta, se retira un rol, y todos los tokens ya emitidos siguen siendo válidos hasta que caduquen. Cuando esa caducidad se mide en horas, un atacante que robó un token conserva el acceso durante horas después de que se bloquee la cuenta.

JWT comparado con una sesión de servidor

Muchos equipos adoptan JWT para sustituir las cookies de sesión sin darse cuenta de que están cambiando una propiedad por otra. El intercambio es este, dicho sin rodeos.

Sesión de servidor Token JWT al portador
Dónde vive el estado En el servidor, en un almacén En el token, en el cliente
Cómo se valida Consultándolo Verificando una firma
Revocación Inmediata: se borra el registro Imposible sin añadir un almacén
Escala entre servicios Necesita un almacén compartido Se verifica donde se conozca la clave
Qué cuesta una fuga Válido hasta que se borre Válido hasta que caduque
Contenido visible para quien lo tiene No Sí, salvo que sea un JWE

La conclusión honesta es que un JWT encaja bien en autorización de corta vida entre servicios, donde quien recibe no puede llegar a un almacén de sesiones, y encaja mal en la sesión de navegador de una sola aplicación, donde una sesión de servidor te regala la revocación. Los equipos que necesitan las dos cosas acaban casi siempre con tokens de acceso cortos más un token de refresco que se guarda y se puede revocar, que es un almacén de sesiones con otro nombre.

Errores frecuentes

Meter secretos en la carga. La puede leer cualquiera que tenga el token, incluidos el navegador, los registros donde se escriba y cualquier proxy del camino.

Caducidad larga para no lidiar con el refresco. Cada hora de validez es una hora de acceso después de descubrir un compromiso. Si los tokens tienen que ser de larga duración, hace falta una lista de revocación, y a esas alturas ya tienes estado en el servidor de todas formas.

Aceptar la clave a la que apunta el token. Los parámetros de cabecera que referencian una clave por URL o que la incrustan directamente son, salvo que quien recibe los ate a un emisor conocido, una invitación a firmar un token con la clave que elija el atacante.

Usar un JWT como cookie de sesión sin las protecciones de cookie. Si el token viaja en una cookie, necesita los mismos atributos de seguridad de cookies y el mismo tratamiento de CSRF que cualquier identificador de sesión. Ser un JWT no cambia nada de eso.

Dar por hecho que el token demuestra la autorización. Demuestra lo que el emisor afirmó en el momento de emitirlo. Si un rol se revocó hace cinco minutos, el token sigue diciendo lo contrario.

Cómo reducirlo

Fija el algoritmo aceptado en el lado que recibe y rechaza cualquier otro, en vez de leer el algoritmo del token. Valida emisor, audiencia, caducidad y no-antes-de en cada petición, y mete esas comprobaciones en una librería compartida para que un servicio nuevo no pueda olvidarlas. Usa firma asimétrica para todo lo que cruce una frontera de confianza, de forma que un servicio que solo verifica no tenga nunca una clave capaz de fabricar tokens. Si usas HS256, el secreto es una clave criptográfica: genérala al azar con la longitud completa y guárdala en un gestor de secretos, no en la configuración.

Mantén cortos los tokens de acceso y pon la revocación donde le toca, en la ruta de refresco o en una lista de bloqueo indexada por identificador de token. Sigue el RFC 8725, el documento de buenas prácticas actuales de JSON Web Token, que existe precisamente porque estos errores se repitieron lo suficiente como para tener que escribirlos.

Para detectar, registra el emisor, la audiencia y el identificador de clave de los tokens rechazados. Una tanda de rechazos con un algoritmo inesperado, o con firma válida y audiencia equivocada, es alguien probando. Los fallos de firma a secas suelen ser desfase de reloj.

Dónde aparece esto en una auditoría

En un informe de API, los hallazgos de JWT se escriben contra el servicio que verifica y contra la comprobación concreta que se saltó, nunca como «implementación insegura de JWT». La evidencia es el token que falsificamos o reproducimos, la afirmación que alteramos y la petición que el servicio aceptó después. Cuando hemos recuperado un secreto HS256, decimos que se crackeó sin conexión a partir de un token emitido a nuestra propia cuenta de prueba, y no ponemos el secreto en el cuerpo del informe.

La severidad sigue a lo que alcanza el token aceptado. Un token falsificado para un usuario del mismo nivel es un hallazgo; un token falsificado cuyas afirmaciones conceden un ámbito administrativo, o que cruza la frontera de un tenant, es otro distinto. Los huecos de revocación se escriben como hallazgo aparte, porque la corrección es arquitectónica y el cliente necesita ver el coste antes de elegir.

Este es un punto fijo cuando probamos la capa de autenticación de una API, junto con los flujos de OAuth 2.0 y las comprobaciones de acceso a nivel de objeto.

Preguntas frecuentes

¿Un JWT va cifrado? Solo si es un JWE. La forma firmada habitual, JWS, va codificada en base64url, que cualquiera puede descodificar. Trata todo lo que haya en la carga como público, y no pongas ahí nada que no le darías al cliente.

¿Sigue siendo relevante el ataque de alg=none? Como comportamiento por defecto lleva mucho tiempo muerto en las librerías mantenidas. Sigue apareciendo en verificaciones hechas a mano, en dependencias antiguas congeladas y en servicios que descodifican el token para leer afirmaciones antes de verificarlo, que es más común de lo que suena.

¿Cómo se revoca un JWT? No se revoca, no en el formato en sí. O esperas a que caduque, o mantienes la vida lo bastante corta como para que esperar sea aceptable, o mantienes estado en el servidor, como una lista de bloqueo o un token de refresco revocable. Quien diga otra cosa ha añadido un almacén en alguna parte.

¿Deberíamos guardar los JWT en localStorage? No. Un valor en localStorage lo puede leer cualquier script del origen, así que un solo fallo de cross-site scripting entrega el token. Una cookie con HttpOnly, Secure y SameSite es el valor por defecto más seguro, con el CSRF tratado de forma explícita.

¿Quieres ver cómo trabajamos en Asperis Security?

Agenda 30 minutos con uno de nuestros especialistas. Revisamos tu stack y te decimos qué conviene probar primero.