Si puede decodificar JWT, ¿cómo son seguros?

302

Si obtengo un JWT y puedo decodificar la carga útil, ¿cómo es eso seguro? ¿No podría simplemente tomar el token del encabezado, decodificar y cambiar la información del usuario en la carga útil y enviarlo de vuelta con el mismo secreto codificado correcto?

Sé que deben ser seguros, pero realmente me gustaría entender las tecnologías. ¿Qué me estoy perdiendo?

PixMach
fuente
2
md5('original messaged' + secret) != md5('changed message' + secret)por lo tanto, si alguien cambia el mensaje, puede detectarlo
Pithikos
cierto para un caso ideal, sin embargo, md5 tiene colisiones. @Pithikos
Yash Kumar Verma
@YashKumarVerma sí, es solo para demostrar lo esencial ya que todos conocen md5.
Pithikos
1
@ user1955934 está codificado en base64, NO encriptado. Simplemente puede decodificarlo con cualquier decodificador base64.
Pithikos
1
Entonces, ¿el cliente deberá enviar el token hash y el jwt? y luego, en el lado del servidor, ¿intentarán hacer hash el token jwt usando secret y compararlo con el hash?
user1955934

Respuestas:

387

Los JWT pueden ser firmados, cifrados o ambos. Si un token está firmado, pero no está encriptado, todos pueden leer su contenido, pero cuando no conoce la clave privada, no puede cambiarla. De lo contrario, el receptor notará que la firma ya no coincidirá.

Responda a su comentario: No estoy seguro si entiendo su comentario de la manera correcta. Solo para estar seguro: ¿conoce y comprende las firmas digitales? Explicaré brevemente una variante (HMAC, que es simétrica, pero hay muchas otras).

Supongamos que Alice quiere enviar un JWT a Bob. Ambos conocen algún secreto compartido. Mallory no conoce ese secreto, pero quiere interferir y cambiar el JWT. Para evitar eso, Alice calcula Hash(payload + secret)y agrega esto como firma.

Al recibir el mensaje, Bob también puede calcular Hash(payload + secret)para verificar si la firma coincide. Sin embargo, si Mallory cambia algo en el contenido, no puede calcular la firma coincidente (que sería Hash(newContent + secret)). Ella no conoce el secreto y no tiene forma de descubrirlo. Esto significa que si ella cambia algo, la firma ya no coincidirá y Bob simplemente ya no aceptará el JWT.

Supongamos que le envío el mensaje a otra persona {"id":1}y lo firmo Hash(content + secret). (+ es solo concatenación aquí). Yo uso la función hash SHA256, y la firma que consigo es: 330e7b0775561c6e95797d4dd306a150046e239986f0a1373230fda0235bda8c. Ahora es tu turno: desempeña el papel de Mallory e intenta firmar el mensaje {"id":2}. No puedes porque no sabes qué secreto usé. Si supongo que el destinatario conoce el secreto, PUEDE calcular la firma de cualquier mensaje y verificar si es correcto.

Misch
fuente
8
Entonces, ¿se cambia la firma cuando se cambia la carga útil? Tenía la impresión de que el token tenía el formato [encabezado]. [Carga útil]. [Firma] ¿se calcula la firma mediante la combinación de la carga útil y el secreto? Si ese fuera el caso, ¿una carga útil con una identificación diferente no sería la misma para ese secreto? Como si los datos fueran {id: 1} y eso se usa para calcular la parte de la firma del token con el secreto, eso no significaría que {id: 2} sería válido para el usuario 2, por lo que el usuario 1 podría cambiar id a 2 y el token sería el mismo?
PixMach
77
Le di un ejemplo para aclarar las cosas, pero no le explicaré todo el concepto de firmas digitales y HMAC. Lea sobre esas cosas, hay mucho material que lo explica.
Misch
11
Oh ahora entiendo. No sé por qué me faltaba la idea de que el hash secreto no sería correcto cuando cambiaste la carga útil porque el hash secreto tendría que ser recalculado. Por alguna razón, todavía pensaba que era independiente. Esa última parte realmente me lo hizo sentir bien. Gracias por acompañarme.
PixMach
30
Tengo una pregunta relacionada. ¿Qué impide que alguien se haga pasar por Alice con el JWT copiado?
Morrowless el
25
Si alguien tiene el JWT, puede hacerse pasar por Alice. Por lo tanto, debe tener cuidado de cómo almacenarlo y enviarlo. También debe establecer una caducidad en la carga útil. De esa forma, si alguien roba el JWT, tiene un plazo limitado para usarlo. Echa un vistazo a stormpath.com/blog/…
Geraint Anderson
134

Puede ir jwt.io, pegar su token y leer el contenido. Esto es discordante para mucha gente inicialmente.

La respuesta corta es que JWT no se preocupa por el cifrado. Se preocupa por la validación. Es decir, siempre puede obtener la respuesta para "¿Se ha manipulado el contenido de este token"? Esto significa que la manipulación por parte del usuario del token JWT es inútil porque el servidor sabrá y no tendrá en cuenta el token. El servidor agrega una firma basada en la carga útil al emitir un token al cliente. Más tarde verifica la carga útil y la firma coincidente.

La pregunta lógica es ¿cuál es la motivación para no preocuparse por los contenidos cifrados?

  1. La razón más simple es porque supone que este es un problema resuelto en su mayor parte. Si se trata de un cliente como el navegador web, por ejemplo, puede almacenar los tokens JWT en una cookie que secure(no se transmite a través de HTTP, solo a través de HTTPS) y httpOnly(no puede ser leída por Javascript) y habla con el servidor a través de Un canal encriptado (HTTPS). Una vez que sepa que tiene un canal seguro entre el servidor y el cliente, puede intercambiar JWT de forma segura o lo que quiera.

  2. Esto mantiene la cosa simple. Una implementación simple facilita la adopción, pero también permite que cada capa haga lo que hace mejor (deje que HTTPS maneje el cifrado).

  3. JWT no está destinado a almacenar datos confidenciales. Una vez que el servidor recibe el token JWT y lo valida, es libre de buscar la ID de usuario en su propia base de datos para obtener información adicional para ese usuario (como permisos, dirección postal, etc.). Esto mantiene a JWT de tamaño pequeño y evita la fuga accidental de información porque todos saben que no deben guardar datos confidenciales en JWT.

No es muy diferente de cómo funcionan las cookies. Las cookies a menudo contienen cargas útiles sin cifrar. Si está utilizando HTTPS, entonces todo está bien. Si no es así, es recomendable cifrar las cookies confidenciales. No hacerlo significará que es posible un ataque de hombre en el medio: un servidor proxy o ISP lee las cookies y luego las reproduce más tarde fingiendo ser usted. Por razones similares, JWT siempre debe intercambiarse por una capa segura como HTTPS.

aleemb
fuente
44
¡Importa! JWT siempre debe intercambiarse por una capa segura como HTTPS
codemirror
Pero si JWT solo es seguro a través de HTTPS, ¿por qué no simplemente enviar la carga útil? POST -> nombre de usuario, contraseña. Todavía está encriptado ¿verdad?
GeekPeek
@GeekPeek para eso deberías leer sobre los conceptos básicos de JWT, pero la autenticación de sesión como mencionas es a menudo todo lo que necesitas. JWT ofrece algunos otros beneficios pero hace algunas compensaciones webskeleton.com/webdev/2019/10/22/…
aleemb
17

El contenido de un token web json (JWT) no es inherentemente seguro, pero hay una función incorporada para verificar la autenticidad del token. Un JWT son tres hashes separados por puntos. El tercero es la firma. En un sistema de clave pública / privada, el emisor firma la firma del token con una clave privada que solo puede ser verificada por su clave pública correspondiente.

Es importante comprender la distinción entre emisor y verificador. El destinatario del token es responsable de verificarlo.

Hay dos pasos críticos para usar JWT de forma segura en una aplicación web: 1) enviarlos a través de un canal encriptado y 2) verificar la firma inmediatamente después de recibirla. La naturaleza asimétrica de la criptografía de clave pública hace posible la verificación de firma JWT. Una clave pública verifica que un JWT fue firmado por su clave privada correspondiente. Ninguna otra combinación de teclas puede hacer esta verificación, evitando así los intentos de suplantación. Siga estos dos pasos y podemos garantizar con certeza matemática la autenticidad de un JWT.

Más información: ¿Cómo una clave pública verifica una firma?

ThisClark
fuente
2

Discutamos desde el principio:

JWT es un enfoque muy moderno, simple y seguro que se extiende a Json Web Tokens. Json Web Tokens son una solución sin estado para la autenticación. Por lo tanto, no es necesario almacenar ningún estado de sesión en el servidor, lo que, por supuesto, es perfecto para API relajantes. Las API de reposo siempre deben estar sin estado, y la alternativa más utilizada para la autenticación con JWT es simplemente almacenar el estado de inicio de sesión del usuario en el servidor mediante sesiones. Pero, por supuesto, no sigue el principio que dice que las API relajantes no deberían tener estado y es por eso que soluciones como JWT se hicieron populares y efectivas.

Entonces, ahora sepamos cómo funciona la autenticación con Json Web Tokens. Asumiendo que ya tenemos un usuario registrado en nuestra base de datos. Entonces, el cliente del usuario comienza haciendo una solicitud de publicación con el nombre de usuario y la contraseña, la aplicación luego verifica si el usuario existe y si la contraseña es correcta, entonces la aplicación generará un Json Web Token único solo para ese usuario.

El token se crea usando una cadena secreta que se almacena en un servidor . A continuación, el servidor envía ese JWT al cliente, que lo almacenará en una cookie o en un almacenamiento local. ingrese la descripción de la imagen aquí

Así, el usuario se autentica y básicamente inicia sesión en nuestra aplicación sin dejar ningún estado en el servidor.

Por lo tanto, el servidor no sabe qué usuario ha iniciado sesión realmente, pero, por supuesto, el usuario sabe que ha iniciado sesión porque tiene un Json Web Token válido, que es un poco como un pasaporte para acceder a partes protegidas de la aplicación.

Así que de nuevo, solo para asegurarte de que tienes la idea. Un usuario inicia sesión tan pronto como recupera su Json Web Token válido único que no se guarda en ningún lugar del servidor. Y, por lo tanto, este proceso es completamente apátrida.

Luego, cada vez que un usuario desea acceder a una ruta protegida, como sus datos de perfil de usuario, por ejemplo. Envía su Json Web Token junto con una solicitud, por lo que es un poco como mostrar su pasaporte para obtener acceso a esa ruta.

Una vez que la solicitud llegue al servidor, nuestra aplicación verificará si el Json Web Token es realmente válido y si el usuario es realmente quien dice ser, entonces los datos solicitados se enviarán al cliente y, de lo contrario, habrá ser un error diciéndole al usuario que no tiene permitido acceder a ese recurso. ingrese la descripción de la imagen aquí

Toda esta comunicación debe realizarse a través de https, por lo que es seguro Http cifrado para evitar que cualquiera pueda acceder a contraseñas o Json Web Tokens. Solo entonces tenemos un sistema realmente seguro.

ingrese la descripción de la imagen aquí

Entonces, un Json Web Token parece parte izquierda de esta captura de pantalla que fue tomada del depurador JWT en jwt.io Así que, esencialmente, es una cadena de codificación compuesta de tres partes. El encabezado, la carga útil y la firma Ahora el encabezado son solo algunos metadatos sobre el token en sí y la carga útil son los datos que podemos codificar en el token, cualquier dato que realmente queramos. Entonces, cuantos más datos queramos codificar aquí, mayor será el JWT. De todos modos, estas dos partes son solo texto sin formato que se codificarán, pero no se cifrarán.

Por lo tanto, cualquiera podrá decodificarlos y leerlos , no podemos almacenar ningún dato confidencial aquí. Pero eso no es un problema en absoluto porque en la tercera parte, así que en la firma, es donde las cosas realmente se ponen interesantes. La firma se crea utilizando el encabezado, la carga útil y el secreto que se guarda en el servidor.

Y todo este proceso se llama firmar el Json Web Token . El algoritmo de firma toma el encabezado, la carga útil y el secreto para crear una firma única. Entonces, solo estos datos más el secreto pueden crear esta firma, ¿de acuerdo? Luego, junto con el encabezado y la carga útil, estas firmas forman el JWT, que luego se envía al cliente. ingrese la descripción de la imagen aquí

Una vez que el servidor recibe un JWT para otorgar acceso a una ruta protegida, necesita verificarlo para determinar si el usuario realmente es quien dice ser. En otras palabras, verificará si nadie cambió el encabezado y los datos de carga del token. Entonces, nuevamente, este paso de verificación verificará si ningún tercero realmente alteró el encabezado o la carga del Json Web Token.

Entonces, ¿cómo funciona realmente esta verificación? Bueno, en realidad es bastante sencillo. Una vez que se recibe el JWT, la verificación tomará su encabezado y carga útil, y junto con el secreto que aún se guarda en el servidor, básicamente crea una firma de prueba.

Pero la firma original que se generó cuando se creó el JWT aún está en el token, ¿verdad? Y esa es la clave de esta verificación. Porque ahora todo lo que tenemos que hacer es comparar la firma de prueba con la firma original. Y si la firma de prueba es la misma que la firma original, significa que la carga útil y el encabezado no se han modificado. ingrese la descripción de la imagen aquí

Porque si hubieran sido modificados, entonces la firma de la prueba tendría que ser diferente. Por lo tanto, en este caso donde no ha habido alteración de los datos, podemos autenticar al usuario. Y, por supuesto, si las dos firmas son realmente diferentes, entonces significa que alguien manipuló los datos. Por lo general, tratando de cambiar la carga útil. Pero ese tercero que manipula la carga útil, por supuesto, no tiene acceso al secreto, por lo que no puede firmar el JWT. Por lo tanto, la firma original nunca corresponderá a los datos manipulados. Y por lo tanto, la verificación siempre fallará en este caso. Y esa es la clave para hacer que todo este sistema funcione. Es la magia que hace que JWT sea tan simple, pero también extremadamente poderoso.

Señor
fuente
1

Solo la clave privada de JWT, que está en su servidor, descifrará el JWT cifrado. Quienes conozcan la clave privada podrán descifrar el JWT cifrado.

Oculte la clave privada en una ubicación segura en su servidor y nunca le diga a nadie la clave privada.

sdfdsf sdf
fuente
1
Los JWT no siempre están encriptados. Se pueden firmar, encriptar, firmar y luego encriptar, o encriptar y luego firmar.
csauve
0

Para las personas que no pueden pagar costosas consultas de bases de datos como yo, una opción para mantener datos confidenciales (privilegios de usuario, etc.) es que, al generar el JWT, puede cifrar estos datos y adjuntarlos al token JWT. (Mantenga la clave de cifrado en el backend)

Cuando desee leer la información confidencial, puede enviar el token JWT al backend y descifrarlo y recuperar la información. De esta manera, no tiene que hacer búsquedas de base de datos o tener la información confidencial desnuda en la interfaz a través del token JWT

Nirojan Selvanathan
fuente
-1

Sugeriría echar un vistazo a JWE utilizando algoritmos especiales que no están presentes en jwt.io para descifrar

Enlace de referencia: https://www.npmjs.com/package/node-webtokens

jwt.generate('PBES2-HS512+A256KW', 'A256GCM', payload, pwd, (error, token) => {
  jwt.parse(token).verify(pwd, (error, parsedToken) => {
    // other statements
  });
});

Esta respuesta puede ser demasiado tarde o puede que ya hayas descubierto el camino, pero aún así, sentí que sería útil para ti y para los demás también.

Un ejemplo simple que he creado: https://github.com/hansiemithun/jwe-example

Mithun Shreevatsa
fuente