proteger por node jsonwebtoken ejemplo bearer basada autenticacion security authentication token jwt secret-key

security - por - proteger api rest



Mejores prácticas para el manejo del servidor de tokens JWT (5)

Aquí hay algunas cosas a tener en cuenta al implementar JWT en su aplicación:

  • Mantenga su vida útil de JWT relativamente corta y haga que su vida útil se administre en el servidor. Si no lo hace, y más tarde necesita requerir más información en sus JWT, deberá admitir 2 versiones o esperar hasta que sus JWT anteriores hayan expirado antes de poder implementar su cambio. Puede administrarlo fácilmente en el servidor si solo mira el campo iat en el jwt e ignora el campo exp .

  • Considere incluir la url de la solicitud en su JWT. Por ejemplo, si desea que su JWT se use en el punto final /my/test/path , incluya un campo como ''url'':''/my/test/path'' en su JWT, para asegurarse de que solo se use en esta ruta. Si no lo hace, es posible que las personas comiencen a usar sus JWT en otros puntos finales, incluso para los que no fueron creados. También podría considerar incluir un md5 (url), ya que tener una gran url en el JWT terminará haciendo que el JWT sea mucho más grande, y pueden llegar a ser bastante grandes.

  • La caducidad de JWT debe ser configurable para cada caso de uso si los JWT se implementan en una API. Por ejemplo, si tiene 10 puntos finales para 10 casos de uso diferentes para JWT, asegúrese de que puede hacer que cada punto final acepte JWT que caduquen en momentos diferentes. Esto le permite bloquear algunos puntos finales más que otros, si, por ejemplo, los datos servidos por un punto final son muy confidenciales.

  • En lugar de simplemente expirar JWT después de un cierto tiempo, considere implementar JWT que admitan ambos:

    • N usos: solo se pueden usar N veces antes de que caduquen y
    • caduca después de cierto tiempo (si tiene una ficha de un solo uso, no quiere que viva para siempre si no se usa, ¿verdad?)
  • Todas las fallas de autenticación JWT deben generar un encabezado de respuesta de "error" que indique por qué falló la autenticación JWT. por ejemplo, "caducado", "no quedan usos", "revocado", etc. Esto ayuda a los implementadores a saber por qué falla su JWT.

  • Considere ignorar el "encabezado" de sus JWT ya que filtran información y dan una medida de control a los piratas informáticos. Esto se refiere principalmente al campo alg en el encabezado: ignore esto y asuma que el encabezado es lo que desea admitir, ya que esto evita que los piratas informáticos intenten usar el algoritmo None , que elimina la comprobación de seguridad de la firma.

  • Los JWT deben incluir un identificador que detalle qué aplicación generó el token. Por ejemplo, si sus JWT están siendo creados por 2 clientes diferentes, mychat y myclassifiedsapp, cada uno debe incluir su nombre de proyecto o algo similar en el campo "iss" en el JWT, por ejemplo, "iss": "mychat"

  • Los JWT no deben registrarse en los archivos de registro. El contenido de un JWT se puede registrar, pero no el JWT en sí. Esto garantiza que los desarrolladores u otros no puedan tomar JWT de los archivos de registro y hacer cosas a las cuentas de otros usuarios.
  • Asegúrese de que su implementación de JWT no permita el algoritmo "Ninguno", para evitar que los hackers creen tokens sin firmarlos. Esta clase de errores se puede evitar por completo ignorando el "encabezado" de su JWT.
  • Considere iat usar iat (emitido a las) en lugar de exp (vencimiento) en sus JWT. ¿Por qué? Dado que iat básicamente significa cuándo se creó el JWT, esto le permite ajustar en el servidor cuando expira el JWT, en función de la fecha de creación. Si alguien aprueba en un exp de 20 años en el futuro, ¡el JWT básicamente vive para siempre! Tenga en cuenta que caduca automáticamente los JWT si su iat está en el futuro, pero permita un poco de margen de maniobra (por ejemplo, 10 segundos), en caso de que el tiempo del cliente esté ligeramente fuera de sincronización con el tiempo del servidor.
  • Considere implementar un punto final para crear JWT a partir de una carga útil json, y obligar a todos sus clientes implementadores a usar este punto final para crear sus JWT. Esto garantiza que pueda abordar cualquier problema de seguridad que desee con la forma en que se crean los JWT en un solo lugar, fácilmente. No lo hicimos directamente en nuestra aplicación, y ahora tenemos que implementar lentamente las actualizaciones de seguridad del lado del servidor JWT porque nuestros 5 clientes diferentes necesitan tiempo para implementarse. Además, haga que su punto final de creación acepte una matriz de cargas útiles json para que los JWT creen, y esto disminuirá el número de solicitudes http que llegan a este punto final para sus clientes.
  • Si sus JWT se usarán en puntos finales que también admiten el uso por sesión, asegúrese de no poner nada en su JWT que sea necesario para satisfacer la solicitud. Puede hacerlo fácilmente si se asegura de que su punto final funcione con una sesión, cuando no se suministra JWT.
  • Entonces, en general, JWT termina conteniendo un ID de usuario o ID de grupo de algún tipo, y permite el acceso a parte de su sistema en función de esta información. Asegúrese de no permitir que los usuarios en un área de su aplicación se hagan pasar por otros usuarios, especialmente si esto proporciona acceso a datos confidenciales. ¿Por qué? Bueno, incluso si su proceso de generación de JWT solo es accesible para servicios "internos", los desarrolladores u otros equipos internos podrían generar JWT para acceder a los datos de cualquier usuario, por ejemplo, el CEO de la empresa de algún cliente aleatorio. Por ejemplo, si su aplicación proporciona acceso a registros financieros para clientes, al generar un JWT, ¡un desarrollador podría obtener los registros financieros de cualquier compañía! Y si un hacker entra en su red interna de todos modos, podría hacer lo mismo.
  • Si va a permitir que cualquier url que contenga un JWT se almacene en caché de alguna manera, asegúrese de que los permisos para diferentes usuarios estén incluidos en la url, y no el JWT. ¿Por qué? Debido a que los usuarios pueden terminar obteniendo datos que no deberían. Por ejemplo, supongamos que un súper usuario inicia sesión en su aplicación y solicita la siguiente URL: /mysite/userInfo?jwt=XXX , y que esta URL se almacena en caché. Cierran sesión y un par de minutos después, un usuario habitual inicia sesión en su aplicación. Obtendrán el contenido en caché, ¡con información sobre un súper usuario! Esto tiende a suceder menos en el cliente y más en el servidor, especialmente en los casos en que está utilizando un CDN como Akamai, y está permitiendo que algunos archivos vivan más tiempo. Esto se puede solucionar al incluir la información de usuario relevante en la url y validarla en el servidor, incluso para solicitudes en caché, por ejemplo /mysite/userInfo?id=52&jwt=XXX
  • Si su jwt está destinado a ser utilizado como una cookie de sesión, y solo debe funcionar en la misma máquina para la que se creó jwt, debe considerar agregar un campo jti a su jwt. Esto es básicamente un token CSRF, que garantiza que su JWT no se pueda pasar del navegador de un usuario a otro.

(generado a partir de este hilo ya que esta es realmente una cuestión propia y no específica de NodeJS, etc.)

Estoy implementando un servidor REST API con autenticación, y he implementado con éxito el manejo de tokens JWT para que un usuario pueda iniciar sesión a través de un punto final / login con nombre de usuario / contraseña, sobre el cual se genera un token JWT desde un secreto del servidor y se devuelve al cliente. Luego, el token se pasa del cliente al servidor en cada solicitud de API autenticada, sobre la cual se utiliza el secreto del servidor para verificar el token.

Sin embargo, estoy tratando de comprender las mejores prácticas para saber exactamente cómo y en qué medida se debe validar el token, para crear un sistema verdaderamente seguro. ¿Exactamente qué debería estar involucrado en "validar" el token? ¿Es suficiente que la firma pueda verificarse usando el secreto del servidor, o también debería verificar el token y / o la carga útil del token con algunos datos almacenados en el servidor?

Un sistema de autenticación basado en token solo será tan seguro como pasar el nombre de usuario / contraseña en cada solicitud, siempre que sea igual o más difícil obtener un token que obtener la contraseña de un usuario. Sin embargo, en los ejemplos que he visto, la única información requerida para producir un token es el nombre de usuario y el secreto del lado del servidor. ¿Esto no significa que, suponiendo por un minuto que un usuario malintencionado obtenga conocimiento del secreto del servidor, ahora puede producir tokens en nombre de cualquier usuario, teniendo así acceso no solo a un usuario dado, como sería el hecho de que una contraseña fuera obtenido, pero de hecho a todas las cuentas de usuario?

Esto me lleva a las preguntas:

1) ¿Debería la validación de token JWT limitarse a verificar la firma del token en sí mismo, confiando solo en la integridad del secreto del servidor o acompañado de un mecanismo de validación separado?

  • En algunos casos, he visto el uso combinado de tokens y sesiones de servidor donde, al iniciar sesión con éxito a través del punto final / login, se establece una sesión. Las solicitudes de API validan el token y también comparan los datos decodificados encontrados en el token con algunos datos almacenados en la sesión. Sin embargo, el uso de sesiones significa el uso de cookies y, en cierto sentido, anula el propósito de usar un enfoque basado en tokens. También puede causar problemas a ciertos clientes.

  • Uno podría imaginar que el servidor mantiene todos los tokens actualmente en uso en una memoria caché o similar, para garantizar que incluso si el secreto del servidor se ve comprometido de manera que un atacante pueda producir tokens "válidos", solo los tokens exactos que se generaron a través del punto final / login Sería aceptado. ¿Es esto razonable o simplemente redundante / excesivo?

2) Si la verificación de la firma JWT es el único medio para validar los tokens, lo que significa que la integridad del secreto del servidor es el punto de ruptura, ¿cómo se deben gestionar los secretos del servidor? ¿Leer desde una variable de entorno y crear (¿aleatorio?) Una vez por pila desplegada? Renovada o rotada periódicamente (y si es así, cómo manejar los tokens válidos existentes que se crearon antes de la rotación pero que deben validarse después de la rotación, tal vez sea suficiente si el servidor mantiene el secreto actual y el secreto anterior en un momento dado) ? ¿Algo más?

Tal vez simplemente estoy siendo demasiado paranoico cuando se trata del riesgo de que el secreto del servidor se vea comprometido, lo que, por supuesto, es un problema más general que debe abordarse en todas las situaciones criptográficas ...



Muchas buenas respuestas aquí. Integraré algunas de las respuestas que considero más relevantes y agregaré algunas sugerencias más.

1) ¿Debería la validación de token JWT limitarse a verificar la firma del token en sí mismo, confiando solo en la integridad del secreto del servidor o acompañado de un mecanismo de validación separado?

No, por razones no relacionadas con el compromiso de un secreto simbólico. Cada vez que un usuario inicia sesión con un nombre de usuario y contraseña, el servidor de autorización debe almacenar el token que se generó o los metadatos sobre el token que se generó. Piense en estos metadatos como un registro de autorización. Un par de usuarios y aplicaciones determinados solo debe tener un token válido o autorización en un momento dado. Los metadatos útiles son la identificación de usuario asociada con el token de acceso, la identificación de la aplicación y el momento en que se emitió el token de acceso (que permite la revocación de tokens de acceso existentes y la emisión de un nuevo token de acceso). En cada solicitud de API, valide que el token contenga los metadatos adecuados. Debe persistir la información sobre cuándo se emitió cada token de acceso, de modo que un usuario pueda revocar los tokens de acceso existentes si sus credenciales de la cuenta están en peligro, e iniciar sesión nuevamente y comenzar a usar un nuevo token de acceso. Eso actualizará la base de datos con la hora en que se emitió el token de acceso (la hora de autorización creada). En cada solicitud de API, verifique que el tiempo de emisión del token de acceso sea posterior al tiempo de autorización creado.

Otras medidas de seguridad incluyeron no registrar JWT y requerir un algoritmo de firma seguro como SHA256.

2) Si la verificación de la firma JWT es el único medio para validar los tokens, lo que significa que la integridad del secreto del servidor es el punto de ruptura, ¿cómo se deben gestionar los secretos del servidor?

El compromiso de los secretos del servidor permitiría a un atacante emitir tokens de acceso para cualquier usuario, y almacenar datos de tokens de acceso en el paso 1 no necesariamente evitaría que el servidor acepte esos tokens de acceso. Por ejemplo, supongamos que a un usuario se le ha emitido un token de acceso, y luego, un atacante genera un token de acceso para ese usuario. El tiempo de autorización del token de acceso sería válido.

Como dice Akshay Dhalwala, si su secreto del lado del servidor se ve comprometido, entonces tiene mayores problemas con los que lidiar porque eso significa que un atacante ha comprometido su red interna, su repositorio de código fuente o ambos.

Sin embargo, un sistema para mitigar el daño de un secreto del servidor comprometido y evitar almacenar secretos en el código fuente implica la rotación del token secreto mediante un servicio de coordinación como https://zookeeper.apache.org . Use un trabajo cron para generar un secreto de la aplicación cada pocas horas más o menos (por mucho tiempo que sus tokens de acceso sean válidos), y envíe el secreto actualizado a Zookeeper. En cada servidor de aplicaciones que necesita conocer el secreto del token, configure un cliente ZK que se actualice cada vez que cambie el valor del nodo ZK. Almacene un secreto primario y un secreto secundario, y cada vez que cambie el secreto del token, establezca el nuevo secreto del token en el primario y el antiguo secreto del token en el secundario. De esa manera, los tokens válidos existentes seguirán siendo válidos porque serán validados contra el secreto secundario. Para cuando el secreto secundario sea reemplazado por el antiguo secreto primario, todos los tokens de acceso emitidos con el secreto secundario expirarían de todos modos.


No creo que sea un experto, pero me gustaría compartir algunas reflexiones sobre Jwt.

  • 1: Como dijo Akshay, es mejor tener un segundo sistema para validar su token.

    a .: La forma en que lo manejo: almaceno el hash generado en un almacenamiento de sesión con el tiempo de expiración. Para validar un token, debe haber sido emitido por el servidor.

    b.:Hay al menos una cosa que debe verificarse con el método de firma utilizado. p.ej :

    header : { "alg": "none", "typ": "JWT" }

Algunas bibliotecas que validan JWT aceptarían esta sin verificar el hash. Eso significa que sin saber su sal utilizada para firmar el token, un pirata informático podría otorgarse algunos derechos. Siempre asegúrese de que esto no pueda suceder. https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/

c .: Usar una cookie con un ID de sesión no sería útil para validar su token. Si alguien quiere secuestrar la sesión de un usuario lambda, solo tendrá que usar un sniffer (por ejemplo: wireshark). Este hacker tendría ambas informaciones al mismo tiempo.

  • 2: Es lo mismo para todos los secretos. Siempre hay una manera de saberlo.

La forma en que lo manejo está vinculada al punto 1.a. : Tengo un secreto mezclado con una variable aleatoria. El secreto es único para cada ficha.

Sin embargo, estoy tratando de comprender las mejores prácticas para saber exactamente cómo y en qué medida se debe validar el token, para crear un sistema verdaderamente seguro.

Si desea la mejor seguridad posible, no debe seguir ciegamente las mejores prácticas. La mejor manera es entender lo que está haciendo (creo que está bien cuando veo su pregunta) y luego evaluar la seguridad que necesita. Y si el Mossad quiere tener acceso a sus datos confidenciales, siempre encontrará la manera. (Me gusta esta publicación de blog: https://www.schneier.com/blog/archives/2015/08/mickens_on_secu.html )


También he estado jugando con tokens para mi aplicación. Si bien no soy un experto de ninguna manera, puedo compartir algunas de mis experiencias y pensamientos sobre el tema.

El objetivo de los JWT es esencialmente la integridad. Proporciona un mecanismo para que su servidor verifique que el token que se le proporcionó es genuino y fue suministrado por su servidor. La firma generada a través de su secreto es lo que proporciona esto. Entonces, sí, si su secreto se filtra de alguna manera, ese individuo puede generar tokens que su servidor consideraría propios. Un sistema basado en tokens aún sería más seguro que su sistema de nombre de usuario / contraseña simplemente por la verificación de la firma. Y en este caso, si alguien tiene su secreto de todos modos, su sistema tiene otros problemas de seguridad con los que lidiar que alguien que hace tokens falsos (e incluso entonces, solo cambiar el secreto asegura que cualquier token hecho con el viejo secreto ahora no sea válido).

En cuanto a la carga útil, la firma solo le indicará que el token que se le proporcionó era exactamente como era cuando su servidor lo envió. la verificación de que los contenidos de las cargas útiles son válidos o apropiados para su aplicación obviamente depende de usted.

Para sus preguntas:

1.) En mi experiencia limitada, definitivamente es mejor verificar tus tokens con un segundo sistema. Simplemente validar la firma solo significa que el token se generó con su secreto. Almacenar cualquier token creado en algún tipo de DB (redis, memcache / sql / mongo, o algún otro almacenamiento) es una forma fantástica de asegurar que solo acepte tokens que su servidor ha creado. En este escenario, incluso si se filtra su secreto, no importará demasiado ya que los tokens generados no serán válidos de todos modos. Este es el enfoque que estoy adoptando con mi sistema: todos los tokens generados se almacenan en un DB (redis) y en cada solicitud, verifico que el token esté en mi DB antes de aceptarlo. De esta forma, los tokens se pueden revocar por cualquier motivo, como los tokens que se liberaron de alguna manera, el cierre de sesión del usuario, los cambios de contraseña, los cambios secretos, etc.

2.) Esto es algo en lo que no tengo mucha experiencia y es algo en lo que todavía estoy investigando activamente, ya que no soy un profesional de seguridad. Si encuentra algún recurso, ¡no dude en publicarlo aquí! Actualmente, solo estoy usando una clave privada que cargo desde el disco, pero obviamente eso está lejos de ser la mejor solución o la más segura.