with node jsonwebtoken example javascript node.js token jwt auth-token

javascript - jsonwebtoken - login with token node js



Las mejores prácticas para invalidar JWT al cambiar las contraseñas y cerrar la sesión en node.js? (5)

Estoy de acuerdo únicamente con @gopinath responder solo quiero agregar una cosa: también debes eliminar el tiempo de contraseña de cambio cuando todos tus tokens caducaron; por ejemplo, supongamos que has configurado el plazo de vencimiento de 3 días para que cada token caduque ahora en lugar de solo guardar el cambio el tiempo de contraseña en la base de datos también puede establecer su tiempo de caducidad de 3 días porque evidentemente los tokens antes de esto expirarán, por lo que no es necesario volver a verificar cada token para saber si el tiempo de caducidad es mayor que cambiar la contraseña o no.

Me gustaría conocer las mejores prácticas para invalidar JWT sin presionar db mientras cambio la contraseña / cerrar la sesión.

Tengo la idea a continuación para manejar los 2 casos anteriores al presionar la base de datos del usuario.

1. En caso de cambios de contraseña, compruebo la contraseña (hash) almacenada en el usuario db.

2. En caso de desconexión, guardo el último tiempo de cierre de sesión en el archivo db del usuario, por lo tanto, comparando el tiempo creado y la hora de cierre de sesión del token, puedo invalidar este caso.

Pero estos 2 casos tienen el costo de golpear al usuario db cada vez que el usuario golpea la API. Cualquier buena práctica es apreciada.

ACTUALIZACIÓN: No creo que podamos invalidar JWT sin pulsar db. Así que se me ocurrió una solución. He publicado mi respuesta, si tiene alguna inquietud, sea bienvenido.


No estoy seguro de si me falta algo aquí, pero me parece que la respuesta aceptada es más complicada de lo necesario.

Veo que se debe presionar db para validar o invalidar un token para cada solicitud de API, sin embargo, el proceso total podría haber sido más simple ya que veo las cosas aquí.

Siempre que se crea un jwt, es decir, durante el inicio de sesión o cambiar / restablecer la contraseña, inserte jwt con userid en una tabla y mantenga un jti (un número de uuid básicamente) para cada jwt. El mismo jti entra en la carga útil jwt también. Efectivamente, jti identifica de manera única a jwt. Un usuario puede tener múltiples jwts al mismo tiempo cuando se accede a la cuenta desde múltiples dispositivos o navegadores, en cuyo caso, jti diferencia el dispositivo o el usuario-agente.

Entonces el esquema de la tabla sería, jti | identidad de usuario. (y una clave principal por supuesto)

Para cada api, compruebe si el jti está en la tabla, lo que significa que el jwt es válido.

Cuando el usuario cambia o restablece la contraseña, elimine todo el jti de ese userId del db. Crea e inserta un jwt nuevo con un jti nuevo en la tabla. Esto invalidará todas las sesiones de todos los demás dispositivos y navegadores excepto el que cambió o restableció la contraseña.

Cuando el usuario cierra la sesión, elimine esa jti particular de ese usuario, pero no todos. Habría un inicio de sesión único, pero no un solo cierre de sesión. Entonces, cuando el usuario cierra la sesión, no debería haber cerrado la sesión desde todos los dispositivos. Sin embargo, al eliminar todos los jtis, también se desconectaría de todos los dispositivos.

Entonces sería una tabla y ninguna comparación de fechas. También sería el mismo caso si se utiliza un token de actualización o no.

Sin embargo, para minimizar la interferencia de DB y las posibles demoras, el uso de la memoria caché sin duda ayudará a facilitar las cosas en el procesamiento del frente de tiempo.

Nota: Por favor, razone si está bajando la votación.


No hay forma de que sepa invalidar arbitrariamente un token sin involucrar una base de datos de una forma u otra.

Tenga cuidado con el Método 2 si se puede acceder a su servicio en varios dispositivos. Considere la siguiente situación ...

  • El usuario inicia sesión con iPad, se emite y almacena el token 1.
  • El usuario inicia sesión en el sitio web. Token 2 emitido. El usuario cierra la sesión.
  • El usuario intenta usar iPad, el token 1 se emitió antes de que el usuario se desconectara del sitio web, el token 1 ahora se considera no válido.

Es posible que desee ver la idea de los tokens de actualización, aunque también requieren el almacenamiento de la base de datos.

También vea here una buena discusión SO sobre un problema similar, la solución particular de IanB que salvaría algunas llamadas a DB.

Solución propuesta Personalmente, así es como me acercaría ... el usuario se autentica, se emite un token de acceso con un vencimiento breve (digamos 15 minutos) y un token de actualización válido por un período mucho más largo o indefinidamente. Almacene un registro de este token de actualización en un db.

Siempre que el usuario esté ''activo'', emita un nuevo token de autenticación cada vez (válido durante 15 minutos cada vez). Si el usuario no está activo durante más de 15 minutos y luego realiza una solicitud (por lo tanto, utiliza un jwt vencido), verifique la validez del token de actualización. Si es válido (incluido el control de db), emita un nuevo token de autenticación.

Si un usuario ''cierra la sesión'' en un dispositivo o en un sitio web, destruya ambos tokens de actualización de acceso del lado del cliente e importantemente revoque la validez del token de actualización utilizado. Si un usuario cambia su contraseña en cualquier dispositivo, entonces revoque todos sus tokens de actualización forzándolos a iniciar sesión de nuevo tan pronto como caduque su token de acceso. Esto deja una "ventana de incertidumbre", pero eso es inevitable sin golpear un db todo el tiempo.

El uso de este enfoque también abre la posibilidad de que los usuarios puedan ''revocar'' el acceso a dispositivos específicos si es necesario, como se ve en muchas aplicaciones web importantes.


Si un usuario está cambiando su contraseña, va a golpear el archivo db allí. ¿Pero no quieres presionar el DB para obtener autorización?

He encontrado los beneficios de almacenar una cadena por usuario, y un hash de cadena compartido global nos da la mayor flexibilidad con nuestra implementación de JWT. En este caso particular, almacenaría un hash de la contraseña para usar con la cadena global y los combinaría para obtener un secreto de JWT.


Cuando se usa el token No Refresh:

1.Mientras cambia la contraseña: cuando el usuario cambia su contraseña, tenga en cuenta la hora de cambio de contraseña en la base de datos del usuario, de modo que cuando la hora de cambio de contraseña sea mayor que la hora de creación del token, el token no sea válido. Por lo tanto, la sesión restante se cerrará pronto.

2. Cuando el usuario cierra la sesión: cuando el usuario cierra sesión, guarde el token en un DB separado (digamos: InvalidTokenDB y elimine el token de Db cuando el token caduque). Por lo tanto, el usuario cierra la sesión del dispositivo respectivo, sus sesiones en otro dispositivo no se alteran.

Por lo tanto, al invalidar un JWT, sigo los siguientes pasos:

  1. Verifica si el token es válido o no.
  2. Si es válido, compruebe que está presente en invalidTokenDB (una base de datos donde los tokens se almacenan hasta su hora de caducidad).
  3. Si no está presente, verifique la hora de creación del token y la hora de contraseña modificada en el db del usuario.
  4. Si se cambió el tiempo de contraseña <tiempo de token creado, entonces el token es válido.

Preocupación con el método anterior :

  1. Para cada solicitud de API, debo seguir todos los pasos anteriores, lo que podría afectar el rendimiento.

Cuando se utiliza el token Refresh: con el token de vencimiento de acceso como 1 día, se actualiza el token como validez de por vida

1. Al cambiar la contraseña: cuando el usuario cambie su contraseña, cambie el token de actualización del usuario. Por lo tanto, la sesión restante se cerrará pronto.

2. Cuando el usuario cierra la sesión : cuando el usuario cierra la sesión, guarde el token en un DB separado (digamos: InvalidTokenDB y elimine el token de Db cuando el token caduque). Por lo tanto, el usuario cierra la sesión del dispositivo respectivo, sus sesiones en otro dispositivo no se alteran.

Por lo tanto, al invalidar un JWT, sigo los siguientes pasos:

  1. comprobar si el token es válido o no
  2. Si es válido, compruebe si el token está presente en InvalidTokenDB.
  3. Si no está presente, verifique el token de actualización con el token de actualización en userDB.
  4. Si es igual, entonces es un token válido

Preocupación con el método anterior :

  1. Para cada solicitud de API, debo seguir todos los pasos anteriores, lo que podría afectar el rendimiento.
  2. Cómo invalidar el token de actualización, ya que el token de actualización no tiene validez, si es utilizado por un hacker, pero la autenticación es válida, la solicitud siempre será exitosa.

Nota : Aunque Hanz sugirió una manera de proteger el token de actualización en el uso de Refesh Token en la autenticación basada en tokens, ¿está asegurado? , No pude entender lo que está diciendo. Cualquier ayuda es apreciada.

Entonces, si alguien tiene una sugerencia agradable, sus comentarios son bienvenidos.

ACTUALIZACIÓN: estoy agregando la respuesta en caso de que su aplicación no necesite un token de actualización con vencimiento de por vida. Esta respuesta fue dada por Sudhanshu ( https://.com/users/4062630/sudhanshu-gaur ). Gracias Sudhanshu. Así que creo que esta es la mejor manera de hacer esto,

Cuando no se necesita el token Refresh y no caducan los tokens de acceso:

cuando el usuario inicia sesión, cree un token de inicio de sesión en su base de datos de usuario sin tiempo de caducidad.

Por lo tanto, al invalidar un JWT, siga los pasos a continuación,

  1. recupera la información del usuario y comprueba si el token está en su base de datos de usuario. Si es así permita.
  2. Cuando el usuario cierra la sesión, elimine solo este token de su base de datos de usuario.
  3. Cuando el usuario cambie su contraseña, elimine todos los tokens de su base de datos de usuario y pídale que vuelva a iniciar sesión.

Por lo tanto, con este enfoque, no es necesario almacenar tokens de cierre de sesión en la base de datos hasta su vencimiento ni almacenar el tiempo de creación del token mientras se cambia la contraseña que se necesitaba en los casos anteriores. Sin embargo, creo que este enfoque solo es válido si su aplicación tiene requisitos sin token de actualización necesario y sin vencimiento de los tokens.

Si alguien tiene alguna preocupación con este enfoque, házmelo saber. Sus comentarios son bienvenidos :)