web-dev-qa-db-fra.com

Où stocker le jeton d'actualisation sur le client?

Mon application SPA utilise l'architecture suivante ( source ):

enter image description here

Cela suppose que mon application cliente connaît le jeton d'actualisation, car j'en ai besoin pour demander un nouveau jeton d'accès si aucun identifiant utilisateur (par exemple, e-mail/mot de passe) n'est présent.

Ma question: Où dois-je stocker le jeton d'actualisation dans mon application côté client? Il y a beaucoup de questions/réponses sur ce sujet sur SO, mais concernant le jeton d'actualisation la réponse n'est pas claire.

Le jeton d'accès et le jeton d'actualisation ne doivent pas être stockés dans le stockage local/de session, car ils ne contiennent pas de données sensibles. Par conséquent, je stocke le jeton d'accès dans un cookie httpOnly (même s'il existe un CSRF) et j'en ai besoin pour la plupart de mes demandes au serveur de ressources de toute façon.

Mais qu'en est-il du jeton d'actualisation? Je ne peux pas le stocker dans un cookie, car (1) il serait également envoyé avec chaque demande à mon serveur de ressources ce qui le rend vulnérable à CSRF aussi et (2) il enverrait exposer le jeton d'accès/rafraîchissement avec un vecteur d'attaque identique.

Il y a trois solutions auxquelles je pourrais penser:


1) Stockage du jeton d'actualisation dans une variable JavaScript en mémoire, qui présente deux inconvénients:

  • a) Il est vulnérable à XSS (mais peut ne pas être aussi évident que le stockage local/de session)
  • b) Il perd la "session" si un utilisateur ferme l'onglet du navigateur

Ce dernier inconvénient, en particulier, se révélera être un mauvais UX.


2) Stocker le jeton d'accès dans le stockage de session et l'envoyer via un Bearer access_token en-tête d'autorisation sur mon serveur de ressources. Ensuite, je peux utiliser des cookies httpOnly pour le jeton d'actualisation. Cela a un inconvénient auquel je peux penser:

  • a) Le jeton d'actualisation est exposé à CSRF avec chaque demande adressée au serveur de ressources.

3) Conservez les deux jetons dans les cookies httpOnly, ce qui présente l'inconvénient mentionné que les deux jetons sont exposés au même vecteur d'attaque.


Il y a peut-être une autre façon ou plus que mes inconvénients mentionnés (veuillez me le faire savoir), mais à la fin tout se résume à où dois-je conserver mon jeton d'actualisation côté client ? Est-ce httpOnly cookie ou une variable JS en mémoire? Si c'est le premier, où dois-je mettre mon jeton d'accès alors?

Serait super heureux d'obtenir des indices sur la façon de procéder de la meilleure façon auprès de personnes qui connaissent le sujet.

8
Robin Wieruch

Vous pouvez stocker les jetons cryptés en toute sécurité dans les cookies HttpOnly.

https://medium.com/@sadnub/simple-and-secure-api-authentication-for-spas-e46bcea592ad

Si vous vous inquiétez du jeton d'actualisation longue durée. Vous pouvez ignorer le stockage et ne pas l'utiliser du tout. Gardez simplement le jeton d'accès en mémoire et effectuez une connexion silencieuse lorsque le jeton d'accès expire.

N'utilisez pas Implicit flow car c'est obsolète .

Le moyen d'authentification le plus sûr pour SPA est Code d'autorisation avec PKCE .

En général, il vaut mieux utiliser les bibliothèques existantes basées sur oidc-client que de construire quelque chose par vous-même.

5
Vladimir Serykh

Vous n'utilisez pas la meilleure architecture d'authentification. Le SPA est un client public et il n'est pas en mesure de stocker en toute sécurité des informations telles qu'un secret client ou un jeton d'actualisation. Vous devez passer à Flux implicite , où les jetons d'actualisation ne sont pas utilisés . Mais Authentification silencieuse (renouvellement silencieux) est disponible à la place.

Je recommande d'utiliser bibliothèque certifiée OIDC , où tout est déjà trié pour les applications SPA. Mon préféré: https://github.com/damienbod/angular-auth-oidc-client

1
Jan Garaj

OAuth définit quatre types de droits: code d'autorisation, implicite, informations d'identification du mot de passe du propriétaire de la ressource et informations d'identification du client. Il fournit également un mécanisme d'extension pour définir des types de subventions supplémentaires.

__ RFC 6749 - Le OAuth 2.0 Framework d'autorisation


Le Authorization Code processus est intrinsèquement conçu pour être utilisé avec un client sécurisé, par exemple. un serveur suffisamment protégé pour contenir le Client Secret à l'intérieur. Si votre client est suffisamment sécurisé pour garder ce secret, mettez simplement le Refresh Token dans le même stockage sécurisé que votre Client Secret.

Ce n'est pas le cas avec les applications hébergées dans User-Agent (UA). Pour ceux-ci, la spécification suggère d'utiliser le type de subvention Implicit qui présente le Access Token après le Redirection URI dans un fragment après # signe. Étant donné que vous recevez le jeton dans le User-Agent directement, c'est intrinsèquement une méthode non sécurisée et vous ne pouvez rien y faire si ce n'est suivre les règles de sécurité de l'agent utilisateur.

Vous pouvez restreindre l'utilisation de votre application à des agents utilisateurs spécifiques, mais cela peut facilement être modifié. Vous pouvez stocker vos jetons dans un cookie, mais celui-ci est également accessible si l'agent d'utilisateur ne respecte pas les normes de sécurité communes. Vous pouvez stocker vos jetons dans le stockage local s'il est implémenté et fourni par l'UA, encore une fois s'il respecte les normes.

La clé de ces autorisations indirectes implicites est la confiance dans l'AU; sinon, le type d'octroi le plus sûr est le code d'autorisation car il nécessite un secret stocké de manière sûre et sécurisée sur un environnement contrôlé (serveur de l'application).

Si vous n'avez pas d'autre choix que d'utiliser l'appel implicite, allez-y simplement et croyez que l'utilisateur utilise un UA sûr qui suit les protocoles de sécurité; de toute façon, vous n'êtes pas responsable du mauvais choix de l'UA par l'utilisateur.

0
Cunning