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

17

Je construis une API RESTful qui utilise des jetons JWT pour l'authentification des utilisateurs (émise par un loginpoint de terminaison et envoyée dans tous les en-têtes par la suite), et les jetons doivent être actualisés après un laps de temps fixe (invocation d'un renewpoint de terminaison, 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. Renvoyez un code http 401 (non autorisé) si la session est devenue invalide ou renvoyez un code 412 (la condition préalable a échoué) lorsque le jeton a expiré et qu'il est temps d'appeler le renewpoint de terminaison, qui renverra un code 200 (ok).
  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 renewpoint de terminaison, s'il renvoie 200, le jeton est actualisé, mais s'il renewrenvoie é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 des 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;)

Óscar López
la source
Comment la session d'un utilisateur deviendrait-elle invalide avant l'expiration du jeton, en supposant un court délai d'expiration (environ 5 minutes)?
Jack
En raison d'une règle métier, une autre partie du système peut invalider la session.
Óscar López
1
Les JWT sont pour la preuve d'identité, comme dans "cette demande est prouvée être de l'utilisateur X". Si votre règle métier est quelque chose comme «l'utilisateur X n'est plus autorisé à interagir avec la ressource Y», c'est quelque chose qui doit être vérifié séparément du JWT.
Jack
@Jack exactement! c'est précisément ce que je veux dire, et la raison pour laquelle je dois utiliser une couche supplémentaire avec état pour enregistrer les informations de session. Le JWT ordinaire, aussi beau soit-il, n'est tout simplement pas fait pour le travail.
Óscar López
1
Vous pouvez être intéressé par ma réponse alors :)
Jack

Réponses:

22

Cela ressemble à un cas d' authentification contre 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 de l' authentification - prouvant que vous êtes bien ce que vous dites être.

Ce que ces revendications signifient pour votre serveur - ce que les utilisateurs et les rôles spécifiques sont autorisés à faire - est le problème de l' 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 Unauthorizedet 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 à longue durée de vie sont stockés sur le client comme des jetons à courte durée de vie, mais ils sont de portée limitée et ne sont utilisés qu'avec votre système d'autorisation pour obtenir des jetons à courte durée de vie. 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 de longue durée 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.

Jack
la source
3
C'est l'orientation que je cherchais, et vous avez apporté un aperçu très pertinent à la discussion - qu'il s'agit d'un cas d'authentification par rapport à l'autorisation, et chacun devrait être traité différemment. Merci!
Óscar López
16

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 doit ê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 Unauthorizedcode de réponse est approprié - et doit appeler le renewpoint de terminaison avec grant_type=refresh_tokenou 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 APIdoit 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 du tout besoin de sessions.

Andy
la source
Merci pour votre réponse. D'accord, l'utilisation d'une session ne serait pas une approche 100% RESTful, mais comme je l'ai mentionné ci-dessus, je dois refuser l'accès à certains utilisateurs avant l'expiration du jeton.
Óscar López
2
@ ÓscarLópez Ensuite, invalidez simplement les jetons que les utilisateurs utilisent. Ils ne pourront plus accéder à l'API à l'aide du jeton fourni (qui sera désormais invalidé) et vous n'avez pas besoin d'une session.
Andy
1
Les jetons sont stockés sur le client, comment puis-je les invalider là-bas? Je devrais garder une trace de ceux qui sont valables ... et c'est là que l'État se lève la tête laide. Parfois, c'est inévitable.
Óscar López
Un client malveillant pourrait continuer à envoyer un jeton précédemment valide aussi longtemps que son temps d'expiration le permet, mais je dois le chasser immédiatement du système.Par conséquent, définir un court délai de renouvellement n'est pas non plus une option.
Óscar López
4
@Laiv J'ai fait le diagramme de séquence dans le bloc-notes.
Andy
1

Donc, j'avoue que cela n'a pas beaucoup de sens de m'inquiéter de l'approche la plus RESTful lorsque vous rompez déjà les conventions REST avec la session, mais je comprends que vous répondez aux exigences de votre entreprise.

D'un point de vue REST, le client est authentifié ou non. L'architecture ne se soucie pas beaucoup du pourquoi (c'est-à-dire injecter un état inutile), donc pour répondre à votre question principale, je n'aurais pas du tout de point final renouvelé. Un client connecté enverra toujours son JWT et le serveur le valide toujours et accepte soit en envoyant le code de réussite approprié basé sur l'action 200, 201, etc.) ou rejette avec un 401 ou 403 selon le cas.

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).

Paul
la source
jwt sont censés être apatrides. au moment où vous
remettez en