web-dev-qa-db-fra.com

Gestion du renouvellement de jeton / de l'expiration de session dans une API RESTful

Je crée une API RESTful qui utilise des jetons JWT pour l'authentification des utilisateurs (émis par un point de terminaison login et envoyé dans tous les en-têtes par la suite), et les jetons doivent être actualisés après un laps de temps fixe (appel d'un renew endpoint, qui renvoie un jeton renouvelé).

Il est possible que la session API d'un utilisateur devienne invalide avant l'expiration du jeton.Par conséquent, tous mes points de terminaison commencent par vérifier que: 1) le jeton est toujours valide et 2) la session de l'utilisateur est toujours valide. Il n'y a aucun moyen d'invalider directement le jeton, car les clients le stockent localement.

Par conséquent, tous mes points de terminaison doivent signaler à mes clients deux conditions possibles: 1) qu'il est temps de renouveler le jeton ou 2) que la session est devenue invalide et qu'ils ne sont plus autorisés à accéder au système. Je peux penser à deux alternatives pour mes points d'extrémité pour signaler à leurs clients lorsqu'une des deux conditions se produit (supposons que les clients peuvent être adaptés à l'une ou l'autre option):

  1. Renvoyer un code http 401 (non autorisé) si la session est devenue invalide ou renvoyer un code 412 (la condition préalable a échoué) lorsque le jeton a expiré et qu'il est temps d'appeler le point de terminaison renew, qui renverra un 200 (ok) code.
  2. Renvoyez 401 pour signaler que la session n'est pas valide ou que le jeton a expiré. Dans ce cas, le client appellera immédiatement le point de terminaison renew, s'il renvoie 200, le jeton est actualisé, mais si renew renvoie également 401, cela signifie que le client est hors du système.

Laquelle des deux alternatives ci-dessus recommanderiez-vous? Laquelle serait plus standard, plus simple à comprendre et/ou plus RESTful? Ou recommanderiez-vous une approche complètement différente? Voyez-vous des problèmes évidents ou des risques de sécurité avec l'une ou l'autre option? Points supplémentaires si votre réponse comprend des références externes qui soutiennent votre opinion.

MISE À JOUR

Les gars, veuillez vous concentrer sur la vraie question - laquelle des deux alternatives de code http pour signaler un renouvellement/invalidation de session est la meilleure? Cela ne me dérange pas que mon système utilise JWT et sessions côté serveur, c'est une particularité de mon API pour des règles métier très spécifiques, et non la partie pour laquelle je demande de l'aide;)

17
Óscar López

Cela ressemble à un cas de authentification versus autorisation.

Les JWT sont des revendications signées cryptographiquement concernant l'expéditeur d'une demande. Un JWT peut contenir des revendications telles que "Cette demande concerne l'utilisateur X" et "L'utilisateur X a un rôle d'administrateur". L'obtention et la fourniture de cette preuve via des mots de passe, des signatures et TLS est le domaine authentification - prouvant que vous êtes bien ce que vous dites être.

Ce que ces revendications signifie à votre serveur - ce que les utilisateurs et les rôles spécifiques sont autorisés à faire - est le problème de autorisation. La différence entre les deux peut être décrite avec deux scénarios. Supposons que Bob veuille entrer dans la section de stockage restreint de l'entrepôt de son entreprise, mais d'abord, il doit traiter avec un garde nommé Jim.

Scénario A - Authentification

  • Bob: "Bonjour Jim, je voudrais entrer dans le stockage restreint."
  • Jim: "Avez-vous votre badge?"
  • Bob: "Non, j'ai oublié."
  • Jim: "Désolé mon pote, pas d'entrée sans badge."

Scénario B - Autorisation

  • Bob: "Bonjour Jim, je voudrais entrer dans le stockage restreint. Voici mon badge."
  • Jim: "Hé Bob, tu as besoin d'une autorisation de niveau 2 pour entrer ici. Désolé."

Les délais d'expiration JWT sont un dispositif d'authentification utilisé pour empêcher les autres de les voler. Si tous vos JWT ont des délais d'expiration de cinq minutes, ce n'est pas si grave s'ils sont volés car ils deviendront rapidement inutiles. Cependant, la règle d'expiration de session dont vous parlez ressemble à un problème d'autorisation. Certains changements d'état signifient que l'utilisateur X n'est plus autorisé à faire quelque chose qu'il était capable de faire auparavant. Par exemple, l'utilisateur Bob a peut-être été licencié - peu importe que son badge indique qu'il est Bob, car le simple fait d'être Bob ne lui donne plus aucune autorité au sein de l'entreprise.

Ces deux cas ont des codes de réponse HTTP distincts: 401 Unauthorized et 403 Forbidden. Le code 401, malheureusement nommé, est destiné aux problèmes d'authentification tels que les informations d'identification manquantes, expirées ou révoquées. 403 est pour l'autorisation, où le serveur sait exactement qui vous êtes mais vous n'êtes tout simplement pas autorisé à faire ce que vous essayez de faire. Dans le cas où le compte d'un utilisateur est supprimé, tenter de faire quelque chose avec un JWT sur un point de terminaison entraînerait une réponse interdite 403. Cependant, si le JWT est expiré, le résultat correct serait 401 non autorisé.

Un modèle JWT commun est d'avoir des jetons "longue durée" et "courte durée". Les jetons de longue durée sont stockés sur le client comme des jetons de courte durée, mais leur portée est limitée et niquement utilisés avec votre système d'autorisation pour obtenir des jetons de courte durée. Les tokens à longue durée de vie, comme leur nom l'indique, ont de très longues périodes d'expiration - vous pouvez les utiliser pour demander de nouveaux tokens pendant des jours ou des semaines. Les jetons de courte durée sont les jetons que vous décrivez, utilisés avec des temps d'expiration très courts pour interagir avec votre système. Les jetons de longue durée sont utiles pour implémenter la fonctionnalité Remember Me, vous n'avez donc pas besoin de fournir votre mot de passe toutes les cinq minutes pour obtenir un nouveau jeton de courte durée.

Le problème d '"invalidation de session" que vous décrivez ressemble à une tentative d'invalidation d'un JWT de longue durée, car ceux de courte durée sont rarement stockés côté serveur tandis que ceux de longue durée sont suivis au cas où ils devraient être révoqués. Dans un tel système, la tentative d'acquérir des informations d'identification avec un jeton de longue durée révoqué entraînerait 401 non autorisé, car l'utilisateur pourrait techniquement être en mesure d'acquérir des informations d'identification, mais le jeton qu'il utilise n'est pas adapté à la tâche. Ensuite, lorsque l'utilisateur tente d'acquérir un nouveau jeton à longue durée de vie en utilisant son nom d'utilisateur et son mot de passe, le système peut répondre avec 403 Interdit s'il est expulsé du système.

22
Jack

Votre session API est une chose qui ne devrait pas exister du tout dans un monde RESTful. Les opérations RESTful sont censées être sans état, la session contient un état et n'a donc pas sa place dans un monde RESTful.

Le JWT devrait être votre seul moyen de déterminer si un utilisateur est toujours éligible pour accéder à un point de terminaison ou non. Une session ne doit absolument y jouer aucun rôle. Si tel est le cas, vous ne disposez pas d'une API RESTful.

Lorsque vous supprimez complètement la session, ce que si vous visez une API RESTful, vous devez le faire et utiliser uniquement le JWT comme facteur d'authentification, un utilisateur est autorisé à utiliser votre point de terminaison ou non - dans ce cas, le 401 Unauthorized le code de réponse est approprié - et doit appeler le point de terminaison renew avec grant_type=refresh_token ou quelle que soit l'identification de renouvellement que vous utilisez.

Mise à jour:

D'après le commentaire, il semble que le flux de validation du JWT que vous utilisez actuellement ne soit pas correct. La validation est censée ressembler à ceci:

  Client        RESTful API      JWT Issuer
     |              |                |
     |----- 1. ---->|                | 
     |              |------ 2. ----->|-----
     |              |                | 3. |
     |              |<----- 4. ------|<----
-----|<---- 5. -----|                |
| 6. |              |                |
---->|----- 7. ---->|                |
     |              |------ 8. ----->|-----
     |              |                | 9. |
     |              |<----- 10. -----|<----
     |              |                |
     |              |------          |
     |              | 11. |          |
     |<---- 12. ----|<-----          |
     |              |                |
     .              .                .

1. Ask RESTful API for a JWT using login endpoint.
2. Ask Issuer to create a new JWT.
3. Create JWT.
4. Return JWT to the RESTful API.
5. Return JWT to Client.
6. Store JWT to append it to all future API requests.
7. Ask for data from API providing JWT as authorization.
8. Send JWT to Issuer for verification.
9. Issuer verifies JWT.
10. Issuer returns 200 OK, verification successful.
11. Retrieve and format data for Client.
12. Return data to Client.

Le serveur, RESTful API, doit vérifier la validité du jeton envoyé en tant qu'autorisation. Ce n'est pas la responsabilité du Client. Il semble que vous ne le fassiez pas actuellement. Implémentez la vérification du JWT de cette façon et vous n'avez pas besoin de sessions du tout.

16
Andy

Donc, je vous avoue que cela n'a pas beaucoup de sens de m'inquiéter de l'approche la plus RESTful lorsque vous rompez déjà REST conventions avec la session, mais je comprends vos besoins commerciaux.

D'un point de vue REST, le client est authentifié, ou ils ne le sont pas. L'architecture ne se soucie pas beaucoup de la raison (qui injecte un état inutile), donc pour répondre à votre question principale, je ne le ferais pas avoir un point de terminaison de renouvellement du tout. Un client connecté enverra juste toujours son JWT et le serveur le validera toujours et acceptera en envoyant le code de réussite approprié basé sur l'action 200, 201, etc.) ou rejettera avec un 401 ou 403 comme approprié.

Maintenant, le JWT va être associé à un compte quelconque. Ce compte peut être verrouillé ou limité ou autre, et le jeton lui-même peut donc être valide, mais l'action peut être rejetée ailleurs. Si le cas est que le compte d'utilisateur est verrouillé en raison de règles commerciales, il s'agit toujours d'un 401 ou 403 selon la quantité d'informations que vous souhaitez donner au client (différentes entreprises ont des opinions différentes à ce sujet).

Enfin, si vous affirmez que le compte peut être déverrouillé et valide mais que le JWT a juste besoin d'être révoqué, je resterais TOUJOURS avec le 401 ou 403 et conserver quelque chose comme une liste de révocation de certificats de JWT invalides dans laquelle vous pouvez en mettre un , tant qu'il se nettoie lorsque le JWT aurait expiré (la plupart des bases de données ont un moyen de le faire ou vous pouvez avoir des événements dans le code d'application).

1
Paul