Los JWT no están encriptados: La #1 idea errónea que causa filtraciones de datos

Cuando los desarrolladores encuentran por primera vez JSON Web Tokens (JWTs), a menudo cometen una suposición peligrosa: el token parece un galimatías encriptado, por lo que los datos internos deben estar seguros. Esta idea errónea ha provocado innumerables brechas de datos, exposición de información personal identificable (PII) y vulnerabilidades severas en aplicaciones de todo el mundo. La verdad incómoda es que los JWT estándar son tan seguros como escribir información sensible en una postal y enviarla por correo postal: cualquiera que la intercepte puede leer cada palabra.
La confusión fundamental
Los JSON Web Tokens se han convertido en el estándar de facto para autenticación en aplicaciones web modernas. Son compactos, autocontenidos y pueden transportar información sobre usuarios y permisos. Sin embargo, las mismas características que hacen que los JWT sean convenientes también los hacen frecuentemente malinterpretados. La idea errónea principal proviene de cómo parecen a los desarrolladores: una larga cadena de caracteres aparentemente aleatorios separada por puntos. Esta apariencia crea una falsa sensación de seguridad que lleva a los desarrolladores a almacenar datos sensibles directamente en la carga útil del token.
La realidad es mucho menos segura de lo que la mayoría de los desarrolladores piensa. Un JWT estándar consta de tres partes separadas por puntos: el encabezado, la carga útil y la firma. Aunque la firma proporciona verificación de integridad mediante firma criptográfica, el encabezado y la carga útil están simplemente codificados en Base64URL—no encriptados. La codificación Base64 es una transformación reversible diseñada para representar datos binarios en formato de cadena ASCII, no como un mecanismo de seguridad. Cualquier persona con conocimientos básicos de programación puede decodificar un JWT en segundos.
Entendiendo la codificación Base64 vs. encriptación
Para entender por qué esto importa, debemos distinguir entre codificación y encriptación. La codificación Base64 es una transformación simple y reversible que convierte datos en un conjunto específico de caracteres. Está diseñada para compatibilidad en transmisión y almacenamiento, no para seguridad. Cada lenguaje de programación incluye funciones integradas para codificar y decodificar Base64 con una sola línea de código. No se requiere contraseña, clave ni secreto para revertir el proceso.
Por otro lado, la encriptación es un proceso criptográfico que transforma datos usando una clave secreta, haciéndolos ilegibles sin esa clave. La verdadera encriptación proporciona confidencialidad—incluso si alguien intercepta datos encriptados, no puede leer su contenido sin la clave de desencriptación. Los JWT firmados con algoritmos como HS256 o RS256 no están encriptados. Están firmados, lo cual es fundamentalmente diferente.
La firma en un JWT cumple una función: verificar que el token no ha sido manipulado y que fue emitido por una fuente confiable. Cuando un servidor crea un JWT, genera una firma hashando el encabezado y la carga útil codificados junto con una clave secreta. Cuando el servidor recibe el token, vuelve a calcular esta firma para verificar su autenticidad. Sin embargo, esta firma no oculta el contenido de la carga útil. Cualquiera puede leer la carga útil; simplemente no puede modificarla sin invalidar la firma.
¿Qué tan fácil es decodificar un JWT?
Sorprendentemente fácil. Veamos un ejemplo con un JWT típico que podrías encontrar en una aplicación web:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIxMjM0NTY3ODkwIiwiZW1haWwiOiJqb2huLmRvZUBleGFtcGxlLmNvbSIsInNzbiI6IjEyMy00NS02Nzg5Iiwic2FsYXJ5Ijo4NTAwMCwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
Para decodificar este token, no necesitas herramientas especializadas ni habilidades de hacking. Puedes visitar jwt.io, un sitio web popular para depuración de JWTs, pegar el token y ver instantáneamente su contenido. Alternativamente, puedes escribir un script simple en cualquier lenguaje de programación. En JavaScript, es literalmente una línea:
JSON.parse(atob(token.split('.')[1]))
En Python, es igualmente sencillo:
import base64, json
json.loads(base64.b64decode(token.split('.')[1] + '=='))
La carga útil decodificada de nuestro ejemplo revelaría:
{
"userId": "1234567890",
"email": "john.doe@example.com",
"ssn": "123-45-6789",
"salary": 85000,
"iat": 1516239022
}
Este ejemplo ilustra una falla de seguridad catastrófica. El token contiene un número de Seguro Social, información salarial y otra información personal que nunca debería transmitirse en un formato legible. Sin embargo, este escenario se presenta en sistemas de producción con más frecuencia de lo que la comunidad de seguridad quisiera admitir.
Impacto real: filtraciones de datos por mal uso de JWT
Las consecuencias de tratar los JWT como contenedores encriptados no son teóricas. Investigadores de seguridad y testers de penetración descubren regularmente aplicaciones que filtran datos sensibles a través de las cargas útiles de JWT. Ejemplos comunes incluyen:
Aplicaciones de salud que almacenan números de registros médicos, códigos de diagnóstico o información de seguros en JWTs. Un actor malicioso que intercepte estos tokens podría acceder a información protegida de salud sin hackear la base de datos.
Plataformas de servicios financieros que incluyen saldos de cuentas, historiales de transacciones o IDs internos de usuarios que corresponden a números de cuenta. Estos tokens, capturados mediante interceptación de red o acceso a JavaScript del cliente, exponen datos financieros directamente.
Sitios de comercio electrónico que incrustan los últimos cuatro dígitos de la tarjeta de crédito, direcciones de envío o historiales de compras en tokens. Aunque los desarrolladores piensen que números parciales de tarjetas son seguros, combinados con otra información filtrada, contribuyen al robo de identidad.
Aplicaciones internas empresariales que colocan IDs de empleados, rangos salariales, calificaciones de rendimiento o información jerárquica en JWTs. Estos tokens, si se exponen mediante herramientas de desarrollo del navegador o registros de red, pueden revelar información confidencial corporativa.
Vulnerabilidades recientes en 2025, como CVE-2025-2079 y CVE-2025-20188, involucraron secretos de JWT codificados en el código que permitían a atacantes generar tokens válidos, pero el problema fundamental va más allá de la gestión de secretos. Incluso con secretos de firma correctamente asegurados, la naturaleza legible de las cargas útiles de JWT presenta un riesgo inherente cuando los desarrolladores almacenan información sensible en ellas.
La anatomía de un JWT: ¿Qué está realmente protegido?
Un JWT consta de tres componentes, cada uno con un propósito específico:
El Encabezado (codificado en Base64URL) especifica el tipo de token y el algoritmo de firma utilizado. Normalmente se ve así:
{
"alg": "HS256",
"typ": "JWT"
}
La Carga útil (codificada en Base64URL) contiene las reclamaciones—afirmaciones sobre una entidad y datos adicionales. Aquí es donde los desarrolladores suelen cometer errores críticos, almacenando información sensible que creen protegida.
La Firma (generada criptográficamente) verifica la integridad del token. Para HS256, se crea hashando el encabezado y la carga útil codificados con una clave secreta usando HMAC-SHA256.
Solo la firma proporciona alguna propiedad de seguridad, y esa propiedad es integridad, no confidencialidad. La firma demuestra que el token no ha sido modificado y que fue emitido por alguien con la clave secreta. No oculta el contenido de la carga útil a ojos curiosos.
¿Qué debería ir realmente en un JWT?
Si los datos sensibles nunca deben aparecer en las cargas útiles de JWT, ¿qué debería ir allí? La respuesta son identificadores y metadatos no sensibles que ayudan al servidor a validar solicitudes y mantener la autenticación sin estado.
Contenidos adecuados para la carga útil de JWT incluyen:
- ID de usuario o nombre de usuario (identificadores no sensibles)
- Tiempo de expiración del token (reclamo exp)
- Marca de tiempo de emisión (reclamo iat)
- Identificación del emisor (iss)
- Identificación del sujeto (sub)
- Especificación de audiencia (aud)
- Roles o permisos no sensibles del usuario
- Identificadores de sesión
El principio clave es que todo en la carga útil debe ser información que te sentirías cómodo mostrando en registros de la aplicación o en la consola del servidor. Si no quieres que esos datos aparezcan en un archivo de registro que otros puedan leer, no pertenecen a una carga útil de JWT.
Para información sensible, mantiene el almacenamiento en servidor con el JWT solo como un identificador de referencia. Cuando el servidor recibe el token, extrae el ID de usuario o identificador de sesión, y busca información adicional en una base de datos segura. Este enfoque mantiene los beneficios de la autenticación sin estado mientras protege los datos sensibles.
La alternativa: Tokens opacos para gestión de sesiones
Muchos expertos en seguridad argumentan que para gestión de sesiones, los tokens opacos ofrecen mejores características de seguridad que los JWT. Un token opaco es una cadena generada aleatoriamente que funciona como clave de consulta para datos de sesión en el servidor. A diferencia de los JWT, los tokens opacos no revelan nada sobre el usuario o la sesión—son verdaderamente sin significado para quien los intercepta.
Al implementar tokens opacos, el servidor genera una cadena aleatoria criptográficamente segura, la asocia con los datos de sesión del usuario en un almacenamiento seguro (como Redis o una base de datos), y devuelve el token al cliente. En solicitudes posteriores, el cliente envía el token, y el servidor busca los datos de sesión asociados. Si el token no existe en el almacenamiento o ha expirado, se rechaza la solicitud.
Esta estrategia ofrece varias ventajas de seguridad. Primero, el contenido del token nunca se expone porque no tiene contenido—solo un identificador aleatorio. Segundo, las sesiones pueden revocarse inmediatamente eliminando el registro en el servidor, algo imposible con JWTs sin estado. Tercero, los datos sensibles de la sesión nunca salen del entorno del servidor.
La desventaja es un aumento en los requisitos de almacenamiento en el servidor y consultas a la base de datos en cada solicitud. Para muchas aplicaciones, especialmente aquellas que manejan datos sensibles, esta compensación vale la pena. Los beneficios de seguridad superan la mínima sobrecarga de rendimiento.
Cuándo son apropiados los JWT
A pesar de estas preocupaciones, los JWT sí tienen casos de uso legítimos donde ofrecen ventajas reales. Son ideales en escenarios que requieren autenticación sin estado en sistemas distribuidos, como arquitecturas de microservicios donde el almacenamiento centralizado de sesiones crearía cuellos de botella.
Los JWT funcionan bien para autenticación API donde el token solo transporta identificadores no sensibles y la puerta de enlace API puede verificar firmas sin consultas a bases de datos. Son útiles para sistemas de inicio de sesión único (SSO) donde varias aplicaciones confían en el mismo emisor y necesitan verificar la autenticación del usuario de forma independiente. También son apropiados para tokens de acceso de corta duración en flujos OAuth 2.0 donde los tiempos de expiración se miden en minutos y operaciones sensibles requieren verificación adicional.
La clave es entender que los JWT proporcionan autenticación y verificación de integridad, no confidencialidad. Cuando se usan correctamente—con datos mínimos en la carga útil y controles de seguridad adecuados—cumplen su propósito. Los problemas surgen cuando los desarrolladores malinterpretan sus propiedades de seguridad y los tratan como contenedores encriptados.
JWE: Cuando realmente necesitas encriptación
Para escenarios que requieren cargas útiles encriptadas, la especificación JWT incluye un hermano menos conocido: JSON Web Encryption (JWE). Los tokens JWE están en realidad encriptados, proporcionando confidencialidad para los contenidos de la carga útil. A diferencia de los JWT estándar (técnicamente llamados JWS—JSON Web Signature), los tokens JWE no pueden ser decodificados sin la clave de encriptación.
Un token JWE tiene cinco partes en lugar de tres, incluyendo encabezados para el algoritmo de encriptación y gestión de claves, una clave encriptada, vector de inicialización, texto cifrado y etiqueta de autenticación. La carga útil está realmente encriptada usando algoritmos como AES-GCM, lo que la hace ilegible para cualquiera sin la clave de desencriptación.
Sin embargo, JWE introduce una complejidad significativa. La gestión de claves se vuelve crítica—perder las claves de encriptación significa perder acceso a todos los tokens encriptados con esas claves. La sobrecarga de rendimiento aumenta debido a operaciones de encriptación y desencriptación. Los errores en la implementación criptográfica pueden crear vulnerabilidades peores que almacenar datos a simple vista.
La mayoría de las aplicaciones no necesitan JWE. La mejor estrategia suele ser mantener los datos sensibles fuera de los tokens por completo, usando almacenamiento en servidor con identificadores referenciados por tokens. JWE debe reservarse para escenarios específicos donde los tokens encriptados ofrecen ventajas claras, como compartir autenticación entre organizaciones con diferentes límites de confianza.
Mejores prácticas para la seguridad de JWT
Implementar autenticación segura basada en JWT requiere seguir prácticas recomendadas que aborden vulnerabilidades comunes:
Nunca almacenes datos sensibles en las cargas útiles de JWT. Esto hay que repetirlo porque es la regla más importante. Trata cada JWT como si fuera a ser leído por un atacante, porque estadísticamente, muchos lo serán.
Usa tiempos de expiración cortos. Mantén los tiempos de vida de los JWT en minutos u horas, no en días o semanas. Los períodos de expiración más cortos limitan el daño de tokens comprometidos.
Implementa mecanismos de actualización de tokens. Emite tokens de acceso de corta duración junto con tokens de actualización de mayor duración almacenados de forma segura. Esto limita la exposición mientras mantiene la conveniencia del usuario.
Valida todas las reclamaciones del JWT. Verifica siempre la firma, comprueba la expiración, valida el emisor y confirma que la audiencia coincida con tu aplicación. Nunca confíes en un JWT sin verificar.
Usa algoritmos de firma fuertes. Prefiere RS256 (firmas RSA) sobre HS256 (HMAC) para mejor separación de claves. Evita ataques de confusión de algoritmos forzando que el servidor acepte solo algoritmos esperados, nunca permitiendo que el encabezado del JWT dicte qué algoritmo usar.
Almacena las claves de firma de forma segura. Nunca codifiques en duro secretos en el código de la aplicación ni los hagas commit en control de versiones. Usa variables de entorno, servicios de gestión de claves o soluciones dedicadas de almacenamiento de secretos.
Implementa HTTPS adecuado. Transmite siempre los JWT en conexiones cifradas. La interceptación en red de tráfico JWT sin cifrar expone los tokens a atacantes.
Considera estrategias de revocación de tokens. Aunque los JWT son sin estado, las aplicaciones críticas deben implementar listas negras o mantener un estado mínimo de sesiones para la capacidad de revocación.
Educar a los equipos de desarrollo
Quizá la medida de seguridad más importante es la educación. La idea errónea de que los JWT ofrecen encriptación persiste porque a los desarrolladores no se les enseña la diferencia entre codificación, firma y encriptación. La capacitación en seguridad debe abordar explícitamente esta brecha, demostrando cuán fácilmente se pueden decodificar los JWT y resaltando las implicaciones.
Los procesos de revisión de código deben marcar cualquier implementación de JWT que almacene datos sensibles en la carga útil. Las herramientas de análisis estático pueden configurarse para detectar patrones comunes de mal uso de JWT. Las pruebas de seguridad deben incluir la revisión del contenido de los JWT en busca de información sensible expuesta.
Las organizaciones deben establecer políticas claras sobre el uso de JWT, especificando qué datos pertenecen a los tokens y cuáles requieren almacenamiento en servidor. La documentación debe incluir ejemplos de implementaciones correctas e incorrectas, haciendo las implicaciones de seguridad muy claras.
Conclusión
La idea errónea de que los JWT proporcionan encriptación ha llevado a innumerables filtraciones de datos y sigue poniendo en riesgo los sistemas. Entender que la codificación Base64 no es encriptación es fundamental para implementar sistemas de autenticación seguros. Los JWT estándar proporcionan verificación de integridad mediante firmas, pero no ofrecen protección de confidencialidad para los contenidos de la carga útil.
Para un desarrollo de aplicaciones seguro, trata las cargas útiles de JWT como datos públicamente legibles. Solo almacena identificadores no sensibles en los tokens, mantiene la información sensible en el servidor y considera tokens opacos para gestión de sesiones en aplicaciones críticas de seguridad. Al implementar JWT, sigue las mejores prácticas, valida todas las reclamaciones del token y usa tiempos de expiración adecuados.
La seguridad de las aplicaciones web modernas depende de que los desarrolladores comprendan las herramientas que usan. Los JWT son poderosos y útiles cuando se aplican correctamente, pero peligrosos cuando se malinterpretan. Reconociendo que los JWT no están encriptados y diseñando sistemas en consecuencia, los desarrolladores pueden aprovechar sus beneficios y evitar las filtraciones de datos que les han dado una mala reputación en círculos de seguridad.
La próxima vez que implementes autenticación basada en JWT, recuerda: si no quisieras que esos datos aparecieran en un archivo de registro del servidor, no deben estar en una carga útil de JWT. La privacidad de tus usuarios y la seguridad de tu aplicación dependen de hacerlo bien.
Related InstaTunnel pages
Continue from this article into the most relevant product guides and workflows.
Related Topics
Keep building with InstaTunnel
Read the docs for implementation details or compare plans before you ship.