web-dev-qa-db-fra.com

Les meilleures pratiques pour invalider JWT lors de la modification des mots de passe et de la déconnexion dans node.js?

J'aimerais connaître les meilleures pratiques pour invalider JWT sans toucher à la base de données en changeant le mot de passe/la déconnexion.

J'ai l'idée ci-dessous de traiter les 2 cas ci-dessus en appuyant sur la base de données des utilisateurs.

1. En cas de changement de mot de passe, je vérifie le mot de passe (haché) stocké dans la base de données utilisateur.

2.En cas de déconnexion, j’économise le temps de dernière déconnexion dans la base de données utilisateur, donc en comparant le temps de création du jeton et le temps de déconnexion, je peux invalider ce cas.

Mais ces 2 cas ont le coût de frapper la base de données utilisateur à chaque fois que l’utilisateur appuie sur l’API. Toute meilleure pratique est appréciée.

PDATE: Je ne pense pas que nous puissions invalider JWT sans frapper la base de données. Alors j'ai trouvé une solution. J'ai posté ma réponse, si vous avez des inquiétudes, vous êtes les bienvenus.

61
Gopinath Shiva

Si aucun jeton d'actualisation n'est utilisé:

1.Pendant la modification du mot de passe: lorsque l'utilisateur modifie son mot de passe, notez l'heure de modification du mot de passe dans la base de données de l'utilisateur. l'heure de création du jeton, le jeton n'est pas valide. Par conséquent, la session restante sera bientôt déconnectée.

2.Lorsque l'utilisateur se déconnecte: Lorsque l'utilisateur se déconnecte, enregistrez le jeton dans une base de données séparée (par exemple: InvalidTokenDB et supprimez le jeton de Db When token expire). Par conséquent, l'utilisateur se déconnecte de l'appareil respectif, ses sessions dans un autre appareil ne sont pas perturbées.

Par conséquent, tout en invalidant un JWT, je suis les étapes ci-dessous:

  1. Vérifiez si le jeton est valide ou non.
  2. S'il est valide, vérifiez qu'il est présent dans invalidTokenDB (une base de données dans laquelle les jetons déconnectés sont stockés jusqu'à leur date d'expiration).
  3. S'il n'est pas présent, vérifiez l'heure de création du jeton et la modification de l'heure du mot de passe dans la base de données utilisateur.
  4. Si le temps de mot de passe modifié est <heure de création du jeton, celui-ci est valide.

Problème avec la méthode ci-dessus :

  1. Pour chaque demande d’API, je dois suivre toutes les étapes ci-dessus, ce qui peut affecter les performances.

Lorsque le jeton d'actualisation est utilisé: avec l'expiration du jeton d'accès à 1 jour, l'actualisation à la validité à vie

1. Lors de la modification du mot de passe: Lorsque l'utilisateur modifie son mot de passe, modifiez le jeton d'actualisation de l'utilisateur. Par conséquent, la session restante sera bientôt déconnectée.

2. Lorsque l'utilisateur se déconnecte : lorsque l'utilisateur se déconnecte, enregistrez le jeton dans une base de données séparée (par exemple: InvalidTokenDB et supprimez le jeton de Db à l'expiration du jeton). Par conséquent, l'utilisateur se déconnecte de l'appareil respectif, ses sessions dans un autre appareil ne sont pas perturbées.

Par conséquent, tout en invalidant un JWT, je suis les étapes ci-dessous:

  1. vérifier si le jeton est valide ou non
  2. S'il est valide, vérifiez si le jeton est présent dans InvalidTokenDB.
  3. S'il n'est pas présent, vérifiez le jeton d'actualisation avec le jeton d'actualisation dans userDB.
  4. Si égal, alors c'est un jeton valide

Problème avec la méthode ci-dessus :

  1. Pour chaque demande d’API, je dois suivre toutes les étapes ci-dessus, ce qui peut affecter les performances.
  2. Comment puis-je invalider le jeton d'actualisation, étant donné que le jeton d'actualisation n'a aucune validité, s'il est utilisé par un pirate informatique, l'authentification est toujours valide, la demande sera toujours couronnée de succès.

Remarque : Bien que Hanz ait suggéré un moyen de sécuriser le jeton d'actualisation dans l'utilisation de Refesh Token dans l'authentification par jeton est sécurisée? , I incapable de comprendre ce qu'il dit. Toute aide est appréciée.

Donc, si quelqu'un a une bonne suggestion, vos commentaires sont les bienvenus.

UPDATE: J'ajoute la réponse si votre application n'a pas besoin de jeton d'actualisation avec une date d'expiration. Cette réponse a été donnée par Sudhanshu ( https://stackoverflow.com/users/4062630/sudhanshu-gaur ). Merci Sudhanshu. Donc, je crois que c'est la meilleure façon de le faire,

Si aucun jeton d'actualisation n'est requis et aucune expiration des jetons d'accès:

lorsque l'utilisateur se connecte, créez un jeton de connexion dans sa base de données d'utilisateurs sans date d'expiration.

Par conséquent, tout en invalidant un JWT, suivez les étapes ci-dessous,

  1. récupérer les informations de l'utilisateur et vérifier si le jeton se trouve dans sa base de données d'utilisateurs. Si oui, permettez.
  2. Lorsque l'utilisateur se déconnecte, supprimez uniquement ce jeton de sa base de données d'utilisateurs.
  3. Lorsque l'utilisateur modifie son mot de passe, supprimez tous les jetons de sa base de données d'utilisateurs et demandez-lui de se reconnecter.

Ainsi, avec cette approche, vous n'avez pas besoin de stocker ni de jetons de déconnexion dans la base de données jusqu'à leur date d'expiration, ni d'enregistrer l'heure de création du jeton lors de la modification du mot de passe nécessaire dans les cas ci-dessus. Cependant, je crois que cette approche ne concerne que les valeurs valides si votre application a des exigences sans qu'un jeton d'actualisation soit nécessaire et sans expiration des jetons.

Si quelqu'un a des préoccupations avec cette approche, s'il vous plaît faites le moi savoir. Vos commentaires sont les bienvenus :)

67
Gopinath Shiva

Je ne connais aucun moyen d'invalider arbitrairement un jeton sans impliquer une base de données d'une manière ou d'une autre.

Soyez prudent avec l'approche 2 si votre service est accessible sur plusieurs appareils. Considérez le scénario suivant ...

  • L'utilisateur se connecte avec iPad, Token 1 émis et stocké.
  • L'utilisateur se connecte sur le site. Jeton 2 émis. L'utilisateur se déconnecte.
  • L'utilisateur essaie d'utiliser l'iPad. Le jeton 1 a été émis avant que l'utilisateur ne se déconnecte du site Web. Le jeton 1 est maintenant considéré comme non valide.

Vous voudrez peut-être examiner l'idée de rafraîchir les jetons bien que ceux-ci nécessitent également un stockage de base de données.

Voir aussi ici pour un bon SO discussion concernant un problème similaire, notamment la solution de IanB qui permettrait de sauver certains appels à la base de données.

Solution proposée Personnellement, voici comment je l'aborderais ... l'utilisateur s'authentifie, se voit attribuer un jeton d'accès avec une expiration courte (disons 15 minutes) et un jeton d'actualisation valide soit pour une période beaucoup plus longue, soit indéfiniment. Stockez un enregistrement de ce jeton d'actualisation dans une base de données.

Chaque fois que l'utilisateur est "actif", émettez un nouveau jeton d'autorisation à chaque fois (valable 15 min à chaque fois). Si l'utilisateur n'est pas actif pendant plus de 15 minutes et qu'il fait ensuite une demande (utilise donc un jwt arrivé à expiration), vérifiez la validité du jeton d'actualisation. S'il est valide (y compris la vérification de la base de données), émettez un nouveau jeton d'authentification.

Si un utilisateur se déconnecte sur un appareil ou via un site Web, détruisez les deux jetons d'actualisation d'accès côté client et révoquez de manière importante la validité du jeton d'actualisation utilisé. Si un utilisateur modifie son mot de passe sur un périphérique, annulez tous ses jetons d'actualisation, l'obligeant à se reconnecter dès l'expiration de son jeton d'accès. Cela laisse une "fenêtre d’incertitude", mais c’est inévitable sans frapper une base de données à chaque fois.

L'utilisation de cette approche offre également la possibilité aux utilisateurs de "révoquer" l'accès à des périphériques spécifiques si nécessaire, comme le montrent de nombreuses applications Web majeures.

14
DevFox

Je ne suis pas sûr qu'il me manque quelque chose mais je trouve que la réponse acceptée est plus compliquée que nécessaire.

Je vois qu'il faut frapper sur la base de données pour valider ou invalider un jeton pour chaque demande d'API, mais le processus total aurait pu être plus simple si je vois les choses ici.

Chaque fois qu'un jwt est créé, c'est-à-dire pendant la connexion ou le changement/réinitialisation du mot de passe, insérez le jwt avec l'ID utilisateur dans une table et conservez un jti (un numéro uuid essentiellement) pour chaque jwt. Le même jti va aussi dans la charge utile jwt. En effet, jti identifie de manière unique un jwt. Un utilisateur peut avoir plusieurs jwts en même temps lorsque le compte est accédé à partir de plusieurs périphériques ou navigateurs, auquel cas jti différencie le périphérique ou l'agent utilisateur.

Donc, le schéma de la table serait, jti | identifiant d'utilisateur. (et une clé primaire de cours)

Pour chaque api, vérifiez si le jti est dans la table, ce qui signifie que le jwt est valide.

Lorsque l'utilisateur modifie ou réinitialise le mot de passe, supprimez tous les jti de cet ID utilisateur de la base. Créez et insérez un nouveau jwt avec un nouveau jti dans la table. Cela invalidera toutes les sessions de tous les autres appareils et navigateurs, à l'exception de celui qui a changé ou réinitialisé le mot de passe.

Lorsque l'utilisateur se déconnecte, supprimez le jti de cet utilisateur, mais pas tous. Il y aurait une seule connexion mais pas une seule déconnexion. Ainsi, lorsque l'utilisateur se déconnecte, il ne devrait pas être déconnecté de tous les appareils. Cependant, la suppression de tous les messages entraînerait également la déconnexion de tous les périphériques.

Donc, ce serait une table et pas de comparaisons de date. Ce serait également le cas si un jeton d'actualisation était utilisé ou non.

Cependant, pour minimiser les interférences de la base de données et les retards éventuels, l’utilisation du cache contribuerait certainement à alléger le temps de traitement.

Note: S'il vous plaît raison si vous votez à la baisse.

7
Amruta-Pani

Si un utilisateur change son mot de passe, vous allez frapper la base de données là-bas. Mais vous ne voulez pas toucher la base de données pour une autorisation?

J'ai trouvé les avantages de stocker une chaîne par utilisateur, et une chaîne partagée mondiale hachée ensemble nous donne la plus grande flexibilité avec notre implémentation JWT. Dans ce cas particulier, je stockais un hachage du mot de passe à utiliser avec la chaîne globale et les hachais ensemble pour obtenir un secret JWT.

1
Mark Essel