web-dev-qa-db-fra.com

Un jeton d'actualisation est-il vraiment nécessaire lors de l'utilisation de l'authentification par jeton JWT?

Je fais référence à un autre SO post qui traite de l'utilisation des jetons de rafraîchissement avec JWT.

JWT (JSON Web Token) prolongation automatique de l'expiration

J'ai une application avec une architecture très courante où mes clients (web et mobile) parlent à une API REST qui parle ensuite à une couche de service et une couche de données.

enter image description here

Je comprends l'authentification par jeton JWT, mais je suis un peu confus quant à la façon d'utiliser les jetons d'actualisation.

Je veux que mon authentification JWT ait les propriétés suivantes:

  1. Le jeton JWT a une expiration de 2 heures.

  2. Le jeton est actualisé toutes les heures par le client.

  3. Si le jeton utilisateur n'est pas actualisé (l'utilisateur est inactif et l'application n'est pas ouverte) et expire, il devra se connecter chaque fois qu'il souhaite reprendre.

Je vois beaucoup de gens qui prétendent en faire une meilleure expérience en utilisant le concept d'un jeton de rafraîchissement, mais je ne vois pas l'avantage de cela. Cela semble être une complexité supplémentaire d'avoir à le gérer.

Mes questions sont les suivantes:

  1. Si je devais utiliser un jeton d'actualisation, ne serait-il pas toujours avantageux d'avoir une expiration à long terme pour les bonnes pratiques sur ce jeton également?
  2. Si je devais utiliser un jeton d'actualisation, ce jeton serait-il conservé avec le jeton userId et/ou JWT?
  3. Lorsque je mets à jour mon jeton toutes les 1 heure, comment cela fonctionne-t-il? Vais-je créer un point de terminaison qui prend mon jeton JWT ou mon jeton d'actualisation? Cela mettra-t-il à jour la date d'expiration de mon jeton JWT d'origine ou créera-t-il un nouveau jeton?
  4. Y a-t-il besoin d'un jeton d'actualisation étant donné ces détails? Il semble que si l'utilisateur utilise simplement un jeton JWT pour récupérer un nouveau jeton (par le lien ci-dessus), le jeton d'actualisation est obsolète.
31
TheJediCowboy

Permettez-moi de répondre à vos questions un peu plus tard et de commencer par discuter de l'objectif global d'un jeton d'actualisation.

La situation est donc:

L'utilisateur ouvre l'application et fournit ses informations de connexion. Maintenant, très probablement, l'application interagit avec un service backend REST. REST étant sans état, il n'y a pas vraiment de moyen d'autoriser l'accès aux API. Par conséquent , jusqu'à présent dans la discussion, il n'y a aucun moyen de vérifier si un utilisateur autorisé accède réellement aux API ou s'il s'agit simplement de quelques requêtes aléatoires.

Maintenant, pour pouvoir résoudre ce problème, nous avons besoin d'un moyen de savoir que les demandes proviennent d'un utilisateur autorisé. Donc, ce que nous avons fait était d'introduire quelque chose appelé un jeton d'accès. Alors maintenant, une fois que l'utilisateur est authentifié avec succès, il reçoit un jeton d'accès. Ce jeton est censé être un jeton long et hautement aléatoire (pour garantir qu'il ne puisse pas être deviné). C'est là que le JWT entre en scène. Maintenant, vous pouvez/pouvez ne pas vouloir stocker de détails spécifiques à l'utilisateur dans un jeton JWT. Idéalement, vous voudriez simplement stocker des détails très simples et extrêmement non sensibles dans le JWT. La manipulation du hachage JWT pour récupérer les détails des autres utilisateurs (IDOR, etc.) est prise en charge par JWT (la bibliothèque utilisée) elle-même.

Donc pour l'instant notre problème d'accès autorisé est résolu.

Maintenant, nous parlons d'un scénario d'attaque. Disons que l'utilisation de tous les utilisateurs ci-dessus Alice, en utilisant l'application, dispose du jeton d'accès autorisé et que son application peut désormais effectuer des requêtes vers toutes les API et récupérer les données conformément à son autorisation.

Supposons que EN QUELQUE SORTE Alice perd le jeton d'accès ou autrement, un adversaire, Bob, obtient l'accès au jeton d'accès d'Alice. Maintenant, Bob, bien qu'il ne soit pas autorisé, peut en fait faire des demandes à toutes les API auxquelles Alice était autorisée.

QUELQUE CHOSE WE IDÉALEMENT NE VEUX PAS.

Maintenant, la solution à ce problème est:

  1. Soit détectez qu'il se passe quelque chose de ce genre.
  2. Réduisez la fenêtre d'attaque elle-même.

En utilisant uniquement le jeton d'accès seul, il est difficile d'atteindre la condition 1 ci-dessus, car que ce soit Alice ou Bob, c'est le même jeton autorisé utilisé et les demandes des deux utilisateurs ne sont donc pas distinguables.

Nous essayons donc d'atteindre 2 ci-dessus et, par conséquent, nous ajoutons une expiration à la validité du jeton d'accès, disons que le jeton d'accès est valide pour le temps "t" (de courte durée).

Comment ça aide? Eh bien, même si Bob a le jeton d'accès, il ne peut l'utiliser que jusqu'à ce qu'il soit valide. Dès son expiration, il devra le récupérer à nouveau. Maintenant, bien sûr, on pourrait dire qu'il peut l'obtenir de la même manière qu'il l'a obtenu la première fois. Mais là encore, rien de tel qu'une sécurité à 100%!

L'approche ci-dessus présente toujours un problème et, dans certains cas, inacceptable en fait. Lorsque le jeton d'accès expire, il faudrait que l'utilisateur entre ses informations de connexion et obtienne à nouveau un jeton d'accès autorisé, ce qui au moins dans le cas des applications mobiles, est une mauvaise expérience utilisateur (non acceptable).

Solution: C'est là qu'intervient le jeton d'actualisation. C'est à nouveau un jeton aléatoire imprévisible qui est également émis vers l'application avec le jeton d'accès en premier lieu. Ce jeton d'actualisation est un jeton spécial à très longue durée de vie, qui garantit que dès que le jeton d'accès expire, il demande au serveur un nouveau jeton d'accès, supprimant ainsi la nécessité pour l'utilisateur de ressaisir ses informations de connexion pour récupérer un nouveau jeton d'accès autorisé, une fois qu'un jeton existant a expiré.

Vous pouvez maintenant demander, Bob peut également avoir accès au jeton d'actualisation, de la même manière qu'il a compromis le jeton d'accès. OUI. Il peut. Cependant, il devient maintenant facile d'identifier une telle incidence, ce qui n'était pas possible dans le cas d'un jeton d'accès seul, et de prendre les mesures nécessaires pour réduire les dommages causés.

Comment?

Pour chaque utilisateur authentifié (dans le cas d'une application mobile, généralement), un jeton d'actualisation mappé un à un et une paire de jetons d'accès sont émis vers l'application. Donc, à un moment donné, pour un seul utilisateur authentifié, il n'y aura qu'un seul jeton d'accès correspondant à un jeton d'actualisation. Supposons maintenant que si Bob a compromis le jeton d'actualisation, il l'utilisera pour générer un jeton d'accès (car le jeton d'accès est la seule chose autorisée à accéder aux ressources via les API). Dès que Bob (attaquant) fait une demande avec le jeton d'accès nouvellement généré, car le jeton d'accès d'Alice (utilisateur authentique) est toujours valide, le serveur verrait cela comme une anomalie, car pour un seul jeton d'actualisation, il ne peut y avoir qu'un seul autorisé jeton d'accès à la fois. Identifiant l'anomalie, le serveur détruirait le jeton d'actualisation en question et avec lui tous ses jetons d'accès associés seront également invalidés. Empêchant ainsi tout accès ultérieur, authentique ou malveillant, à toute autorisation nécessitant des ressources. L'utilisateur, Alice, devrait à nouveau s'authentifier avec ses informations d'identification et récupérer une paire valide de jetons d'actualisation et d'accès.

Bien sûr, vous pouvez toujours affirmer que Bob pourrait à nouveau avoir accès à la fois aux jetons d'actualisation et d'accès et répéter toute l'histoire ci-dessus, ce qui pourrait conduire à un DoS sur Alice, le véritable client réel, mais là encore, il n'y a rien de mieux que la sécurité à 100% .

Également comme bonne pratique, le jeton d'actualisation devrait également avoir une expiration, bien que assez longue.

40
qre0ct

Je pense que pour ce scénario, vous pouvez travailler avec le jeton d'accès seul, simplifier la vie de vos clients tout en conservant les avantages de sécurité d'un jeton d'actualisation.

Voici comment cela fonctionnerait:

  1. Lorsque votre utilisateur se connecte avec des informations d'identification (nom d'utilisateur/mot de passe), vous renvoyez un JWT de courte durée. Vous créez également un enregistrement db où vous stockez:

    • ID JWT
    • identifiant d'utilisateur
    • Adresse IP
    • agent utilisateur
    • un indicateur valid (par défaut TRUE)
    • créé à
    • mis à jour
  2. Votre client soumet le JWT à chaque demande. Tant que le JWT n'a pas expiré, il a accès aux ressources. Si le JWT a expiré, vous le rafraîchissez en arrière-plan et renvoyez à la fois la ressource et un X-JWT en-tête avec le nouveau JWT.

  3. Lorsque le client reçoit une réponse avec un X-JWT header, il supprime l'ancien JWT et utilise le nouveau pour les demandes futures.

Comment l'actualisation du JWT fonctionne sur le serveur

  1. Recherchez l'enregistrement de base de données correspondant à l'aide de l'ID JWT.
  2. Vérifiez si l'indicateur valid est toujours vrai, sinon rejetez.
  3. Facultativement, vous pouvez comparer l'adresse IP et l'agent utilisateur de la demande à l'adresse IP et à l'agent utilisateur stockés, et décider de rejeter si quelque chose semble louche.
  4. Vous pouvez éventuellement vérifier les champs createdAt ou updatedAt de l'enregistrement db et décider de ne pas actualiser si trop de temps s'est écoulé.
  5. Mettez à jour le champ updatedAt dans l'enregistrement db.
  6. Renvoyez le nouveau JWT (qui est essentiellement une copie du JWT expiré, mais avec un délai d'expiration prolongé).

Cette conception vous donnerait également la possibilité de révoquer tous les jetons d'un utilisateur (par exemple, si l'utilisateur perd son téléphone ou met à jour son mot de passe).

Avantages:

  • Votre client n'a jamais à vérifier les délais d'expiration ou à effectuer des demandes d'actualisation de jeton, il ne fait que rechercher un X-JWT en-tête sur les réponses.
  • Vous pouvez ajouter une logique d'actualisation personnalisée basée sur l'adresse IP, l'agent utilisateur, l'âge maximal du jeton ou une combinaison de ceux-ci.
  • Vous pouvez révoquer certains ou tous les jetons d'un utilisateur.
8
alexishevia

Si je devais utiliser un jeton d'actualisation, ne serait-il pas toujours avantageux d'avoir une expiration à long terme pour les bonnes pratiques sur ce jeton également?

Les jetons d'actualisation sont de longue durée, les jetons d'accès sont de courte durée.

Si je devais utiliser un jeton d'actualisation, ce jeton serait-il conservé avec le jeton userId et/ou JWT?

Il serait conservé en tant que jeton distinct sur le client, aux côtés de JWT mais pas à l'intérieur de JWT. UserID/UID peut être stocké à l'intérieur du jeton JWT lui-même.

Lorsque je mets à jour mon jeton toutes les 1 heure, comment cela fonctionne-t-il? Vais-je créer un point de terminaison qui prend mon jeton JWT ou mon jeton d'actualisation? Cela mettra-t-il à jour la date d'expiration de mon jeton JWT d'origine ou créera-t-il un nouveau jeton?

Oui, vous avez besoin d'un service distinct qui émet et actualise le jeton. Il ne mettra pas à jour l'expiration du jeton JWT existant. Un jeton est simplement une paire de valeurs de champ JSON codée en base64. Donc, changer les données change la sortie. Le jeton a également la date d'émission, qui changera à tout le moins à chaque nouvelle émission (actualisation). Ainsi, chaque jeton sera unique et nouveau. Les anciens jetons expireront automatiquement, vous devez donc expirer tous les jetons d'accès, sinon ils resteront éternellement.

L'autre réponse indique ici que les anciens jetons sont détruits lorsque vous émettez un nouveau jeton. Ce n'est tout simplement pas le cas. Les jetons ne peuvent pas être détruits. En fait, vous pouvez récolter des centaines de jetons en contactant constamment le serveur d'authentification et en demandant de nouveaux jetons à l'aide de votre jeton d'actualisation. Chacun de ces jetons d'accès sera valable jusqu'à leur expiration. L'expiration est donc impérative et devrait être courte.

Y a-t-il vraiment besoin d'un jeton d'actualisation étant donné ces détails? Il semble que si l'utilisateur utilise simplement un jeton JWT pour récupérer un nouveau jeton (par le lien ci-dessus), le jeton d'actualisation est obsolète.

Les jetons JWT ont des revendications client. Par exemple is_manager:true une revendication sur un jeton JWT peut autoriser l'accès aux fonctionnalités de niveau gestionnaire. Maintenant, si vous décidez de rétrograder l'utilisateur de gestionnaire à entrepreneur, cela ne prendra pas effet immédiatement. L'utilisateur peut toujours utiliser l'ancien jeton. Enfin, lorsque celui-ci expire, il frappe le serveur d'authentification pour rafraîchir son jeton. Le serveur d'authentification émet un nouveau jeton sans revendication de gestion et l'utilisateur ne pourra plus accéder aux fonctionnalités de gestion. Cela crée une fenêtre pendant laquelle les revendications de l'utilisateur ne sont pas synchronisées avec le serveur. Cela explique à nouveau pourquoi les jetons d'accès doivent être de courte durée afin que la synchronisation puisse se produire souvent.

Essentiellement, vous mettez à jour les vérifications d'autorisation toutes les 15 minutes, au lieu de les vérifier à chaque demande (c'est ainsi que fonctionne l'authentification basée sur la session). Si vous voulez des autorisations en temps réel au lieu de rafraîchissements toutes les 15 minutes, alors JWT peut ne pas être un bon ajustement .

0
aleemb