Iniciando con JWT (JSON Web Token)

Iniciando con JWT (JSON Web Token)

¡Bienvenido(a) al mundo de los JSON Web Tokens, también conocidos como JWTs!

JWT (JSON Web Token) es un estándar abierto que permite transmitir información de forma segura entre diferentes partes utilizando un formato compacto y autónomo en formato JSON. Se usa ampliamente para autenticación y autorización en aplicaciones web y APIs. En este artículo, exploraremos qué es JWT, cómo funciona, sus ventajas y desventajas, posibles vulnerabilidades, cuándo debemos utilizarlo y las mejores prácticas para implementarlo.

¡Vamos allá!

Introducción a los JSON Web Tokens (JWT)

¿Has oído hablar de los JWTs? Son como mensajes secretos que se transmiten entre diferentes partes en forma de un objeto JSON compacto. Es como si estuvieras enviando una nota secreta a un amigo, pero en lugar de un trozo de papel, usas un JSON.

Estos JWTs son muy útiles en aplicaciones web y APIs. Se utilizan principalmente para autenticación y autorización. Cuando quieres autenticarte en un sitio o aplicación, generalmente necesitas proporcionar un nombre de usuario y una contraseña, ¿verdad? Lo que hace el servidor es verificar esa información y, si es correcta, crea un JWT especial para ti.

Ese JWT contiene información sobre ti, como tu ID de usuario y tal vez hasta tu nombre. Pero lo genial de los JWTs es que son autónomos. Esto significa que toda la información necesaria está contenida dentro del propio JWT, por lo que no es necesario consultar una base de datos u otro lugar para obtener los detalles; ¡todo está allí!

Y como el JWT es compacto, puede transmitirse fácilmente por Internet. Es como si enviaras un mensaje importante en un sobre pequeño y seguro. Pueden ser enviados como parte de las solicitudes que haces al servidor o incluso incluidos en URLs.

Ahora, ¡vamos a entender más sobre su estructura y cómo funciona realmente!

Estructura del JWT

Antes de sumergirnos en los detalles, es importante entender cómo se construye un JWT.

Un JWT consiste en tres partes principales: el encabezado (header), la carga útil (payload) y la firma (signature). Estas partes se codifican y se juntan con puntos para formar el JWT completo.

1. Encabezado (Header): El encabezado contiene información sobre el JWT, como el tipo de token (typ) y el algoritmo de firma (alg). El campo typ especifica el tipo de token, que generalmente se define como "JWT". El campo alg identifica el algoritmo usado para firmar el token. Hay diferentes algoritmos disponibles, como HMAC SHA256 o RSA, que se utilizan para crear esta firma especial. Es como elegir qué sello usar para garantizar que el JWT sea válido y confiable.

Un ejemplo de encabezado de JWT:


2. Carga Útil (Payload): La carga útil transporta las declaraciones (claims), que son afirmaciones sobre una entidad (por ejemplo, usuario) y metadatos adicionales. Las declaraciones pueden clasificarse en tres tipos: declaraciones registradas (registered claims), declaraciones públicas (public claims) y declaraciones privadas (private claims).

Veamos algunos ejemplos:

  • Declaraciones registradas: Son declaraciones predefinidas recomendadas por la especificación JWT, que incluyen iss (emisor), sub (asunto), exp (hora de expiración) e iat (hora de emisión).
  • Declaraciones públicas: Son declaraciones personalizadas hechas por los usuarios de los JWTs. Pueden contener información específica y son definidas por el propio usuario. Estas declaraciones pueden crearse siguiendo dos opciones:

1.1 Definiéndolas en el Registro JSON Web Token de la IANA: Existen algunas declaraciones comunes ya definidas que puedes usar.

1.2  Definiéndolas como una dirección en internet (URI) que sea única y no genere conflictos con otros identificadores.

  • Declaraciones privadas: Son declaraciones personalizadas específicas de una aplicación u organización. Se usan para compartir información entre las partes que están de acuerdo con lo que significan estas declaraciones. En otras palabras, las declaraciones privadas son como secretos compartidos entre un grupo selecto de personas o sistemas que entienden su significado. Permiten que añadas información especial a tu JWT para satisfacer las necesidades específicas de tu aplicación u organización.


3. Firma (Signature): La firma se crea combinando el encabezado codificado (header), la carga útil codificada (payload) y una clave secreta usando el algoritmo especificado. La firma garantiza la integridad y autenticidad del token. Puede ser usada por el destinatario para verificar la autenticidad del token y detectar cualquier intento de alteración.

Un ejemplo de firma de JWT (usando el algoritmo HMAC SHA256):

El encabezado codificado, la carga útil codificada y la firma se concatenan con puntos para formar el JWT final.

Cómo funciona el JWT

Ahora que sabemos cómo es la estructura del JWT, vamos a entender cómo realmente funciona en un escenario común: la autenticación de usuarios y el control de acceso en una aplicación web.

1. Autenticación: Cuando un usuario proporciona sus credenciales (por ejemplo, nombre de usuario y contraseña) al servidor, el servidor verifica las credenciales. Si las credenciales son válidas, el servidor genera un JWT como token de autenticación.

2. Generación del Token: El servidor construye una carga útil (payload) que contiene información relevante sobre el usuario, como el ID del usuario, nombre de usuario y cualquier declaración necesaria. Luego, el servidor firma la carga útil con una clave secreta usando un algoritmo de firma especificado. El JWT resultante se devuelve al cliente como parte de la respuesta de autenticación.

Aquí tienes un ejemplo en Node.js usando la biblioteca jsonwebtoken:


En este ejemplo, la biblioteca jsonwebtoken se usa para generar un JWT. El objeto payload contiene las declaraciones e información relevante sobre el usuario. La secretKey es una clave compartida entre el servidor y el cliente, utilizada para firmar y verificar el token. La función jwt.sign firma la carga útil con la clave secreta (secretKey) y el JWT resultante se imprime en la consola.

3. Almacenamiento del Token: El cliente normalmente almacena el JWT recibido de forma segura, como en un almacenamiento local (local storage) o en una cookie, para incluirlo en solicitudes subsecuentes al servidor.

4. Control de Acceso: Cuando el cliente desea acceder a un recurso protegido en el servidor, incluye el JWT en la solicitud, generalmente como un encabezado HTTP (por ejemplo, Authorization: Bearer <JWT>).

5. Verificación del Token: El servidor recibe la solicitud y extrae el JWT del encabezado HTTP. Luego, verifica la firma del JWT usando la clave secreta. Si la firma es válida, el servidor decodifica la carga útil para obtener la información del usuario y realiza verificaciones adicionales, como la verificación del tiempo de expiración, para garantizar que el token aún sea válido.

Ahora la misma biblioteca jsonwebtoken para verificar un JWT:


En este ejemplo, la función jwt.verify se usa para verificar el JWT. La variable token contiene el JWT a ser verificado y la secretKey es la clave secreta compartida utilizada para firmar y verificar el token. Si la verificación es exitosa, la carga útil decodificada se imprime en la consola.

6. Concesión de Acceso: Si el JWT es válido y todas las verificaciones pasan, el servidor concede acceso al recurso solicitado, sabiendo que el usuario ha sido autenticado.

Podemos entender que los JWTs guardan información de autenticación y autorización, permitiendo acceder a partes especiales de un sitio sin necesidad de recordar todo en el servidor. Son perfectos para sistemas distribuidos y aplicaciones modernas con varias partes trabajando juntas, haciéndolos adecuados para sistemas distribuidos y arquitecturas de microservicios.

Ventajas del Uso de JWT

Aquí están las razones por las cuales los JWTs son tan populares en aplicaciones web y APIs:

1. Autosuficientes (Self-contained): Como se mencionó anteriormente, los JWTs son autosuficientes, lo que significa que toda la información necesaria está contenida en ellos. Eliminan la necesidad de consultar la base de datos o el servidor de autenticación en cada solicitud, reduciendo la carga del servidor y mejorando la escalabilidad.

2. Formato Compacto: El formato compacto del JSON es adecuado para entornos con ancho de banda limitado, lo que hace que los JWTs sean fáciles de transmitir por la red, ya sea como parte del encabezado HTTP o en la URL.

3. Seguros (Secure): Los JWTs pueden ser firmados digitalmente usando algoritmos criptográficos seguros, como HMAC SHA256 o RSA. Esto garantiza que los tokens no sean alterados durante la transmisión y que solo el servidor confiable pueda crear y validar los tokens.

4. Uso en Varios Dominios (Cross-domain): Debido a su naturaleza autosuficiente, los JWTs pueden ser fácilmente utilizados en varios dominios o subdominios. Esto es una ventaja importante cuando se trabaja con APIs públicas o sistemas distribuidos.

5. Cache y Performance: Como los JWTs pueden incluir un tiempo de expiración (exp), los clientes pueden almacenarlos en caché y evitar la necesidad de renovar el token en cada solicitud. Esto mejora el rendimiento y reduce la carga en los servidores de autenticación.

6. Flexibilidad en las Declaraciones: Los JWTs permiten declaraciones públicas y privadas personalizadas, haciéndolos flexibles para satisfacer las necesidades específicas de una aplicación.

Desventajas del Uso de JWT

A pesar de las ventajas, los JWTs también tienen algunas desventajas y es importante considerarlas al decidir usarlos:

1. Tamaño del Token: Como los JWTs almacenan información directamente en el token, pueden volverse grandes si se incluyen muchos datos. Esto puede aumentar el tamaño de la carga útil y, consecuentemente, aumentar el tráfico de red.

2. Seguridad de los Tokens Almacenados en el Cliente: Por defecto, los JWTs se almacenan en el cliente (por ejemplo, en cookies o almacenamiento local). Si un token es robado o comprometido, un atacante podría usarlo para acceder a recursos protegidos. Para mitigar este riesgo, es esencial usar mecanismos adecuados de protección de cookies y adoptar prácticas de seguridad, como la renovación periódica del token.

3. Falta de Control Centralizado: Los JWTs son autosuficientes y firmados por el servidor de autenticación. Esto significa que, si un token necesita ser revocado antes del tiempo de expiración, no hay un mecanismo de invalidación centralizado. La revocación requerirá estrategias adicionales, como listas de revocación (blacklists) o uso de tokens de corta duración.

4. Dependencia del Reloj del Cliente: La verificación del tiempo de expiración del token se hace en el cliente. Esto puede llevar a problemas de sincronización del reloj, donde el tiempo del cliente puede estar desactualizado y resultar en problemas de autenticación.

Posibles Vulnerabilidades y Mejores Práticas

Aunque los JWTs son una opción popular para autenticación y autorización, también están sujetos a varias vulnerabilidades comunes, como:

1. Ataques de Fuerza Bruta y Diccionario: Si la clave secreta usada para firmar los tokens es débil, los atacantes pueden intentar adivinar la clave usando ataques de fuerza bruta o diccionario. Por lo tanto, es esencial usar una clave fuerte y compleja.

2. Exposición a Ataques XSS: Los JWTs almacenados en cookies pueden ser vulnerables a ataques de Cross-Site Scripting (XSS), donde un atacante puede robar el token mediante scripts maliciosos inyectados en páginas del cliente. Para mitigar este riesgo, es importante usar protecciones adecuadas contra XSS, como la configuración de políticas de seguridad de contenido (Content Security Policy).

3. Fuga de Información Confidencial: Es crucial evitar incluir información confidencial o sensible en el cuerpo del JWT, ya que es decodificado en el cliente y puede ser leído por cualquiera. Información como contraseñas o detalles financieros deben ser almacenados en el servidor, no en el JWT.

4. No Confíes Solamente en el JWT para Autorización: Aunque los JWTs pueden contener declaraciones de autorización (por ejemplo, niveles de acceso), no dependas exclusivamente del JWT para controlar el acceso a los recursos. Verifica los permisos y autorizaciones en el servidor antes de conceder acceso.

5. Mantén los Tokens con Duración Corta: Tokens con duración corta reducen el riesgo de compromiso a largo plazo, ya que expiran después de un corto período de tiempo. Usa tiempos de expiración apropiados basados en los requisitos de la aplicación.

Casos de uso

Los JWTs son ampliamente utilizados en varios escenarios, tales como:

  • Autenticación de Usuarios: Al iniciar sesión, se genera un JWT y se envía al cliente, permitiéndole acceder a recursos protegidos sin la necesidad de reenviar las credenciales en cada solicitud. Esto ofrece una experiencia de autenticación más eficiente, ya que el cliente puede almacenar el token y enviarlo en cada solicitud para probar su identidad.

Ejemplo de respuesta de autenticación con JWT:

  • Autorización de Acceso: Los JWTs pueden contener declaraciones de autorización, como niveles de acceso, permitiendo que el servidor controle qué recursos el cliente puede acceder. Por ejemplo, un JWT puede contener información sobre el rol del usuario (administrador, usuario común, etc.) y el servidor puede verificar esta información antes de conceder acceso a recursos sensibles.

Ejemplo de JWT con declaración de autorización:

  • Comunicación entre Microservicios: En entornos de microservicios, los JWTs son utilizados para autenticar y autorizar la comunicación entre diferentes servicios. Cada servicio puede generar un JWT con información relevante sobre el origen de la solicitud y enviarlo a otros servicios para permitir una comunicación segura y confiable.

Ejemplo de JWT usado en la comunicación entre microservicios:

  • Sistemas Distribuidos: En sistemas distribuidos, los JWTs permiten que diferentes partes de la aplicación se comuniquen de forma segura y autónoma. Cada componente puede generar un JWT que contenga información necesaria para la comunicación y luego enviar el token a otras partes para garantizar la autenticidad e integridad de los datos intercambiados.

Ejemplo de JWT usado en sistemas distribuidos:

Estos son solo algunos ejemplos de cómo los JWTs pueden ser utilizados en diferentes escenarios. Su versatilidad, seguridad y capacidad de transportar información los convierten en una opción muy poderosa para la autenticación y autorización en entornos variados, desde aplicaciones web hasta sistemas distribuidos complejos.

Conclusión

¡Espero que ahora te sientas más cómodo con el mundo de los JWTs! Son realmente una herramienta poderosa para la autenticación y autorización en aplicaciones web y APIs. Su naturaleza autosuficiente, formato compacto y capacidad de firma digital los convierten en una elección popular para sistemas distribuidos y entornos de microservicios. Sin embargo, es esencial entender las mejores prácticas y las vulnerabilidades potenciales para usarlos de manera segura.

Antes de adoptar los JWT, se recomienda evaluar los requisitos de seguridad y los casos de uso específicos de la aplicación. Al tomar decisiones bien informadas y seguir las mejores prácticas de seguridad, puedes garantizar que los JWTs sean usados efectivamente para proteger tu aplicación y datos sensibles.

Espero que este artículo haya sido informativo y útil. Si tienes más dudas o necesitas más aclaraciones, siéntete libre de preguntar.

¡Buena implementación de JSON Web Tokens! 🚀

💡
Las opiniones y comentarios emitidos en este artículo son propiedad única de su autor y no necesariamente representan el punto de vista de Listopro.

Listopro Community da la bienvenida a todas las razas, etnias, nacionalidades, credos, géneros, orientaciones, puntos de vista e ideologías, siempre y cuando promuevan la diversidad, la equidad, la inclusión y el crecimiento profesional de los profesionales en tecnología.