Et si JWT est volé?

201

J'essaie d'implémenter l'authentification sans état avec JWT pour mes API RESTful.

AFAIK, JWT est essentiellement une chaîne chiffrée transmise en tant qu'en-têtes HTTP lors d'un appel REST.

Mais que se passe-t-il s'il y a un espion qui voit la demande et vole le jeton ? Ensuite, il pourra faire une fausse demande avec mon identité?

En fait, cette préoccupation s'applique à toutes les authentifications basées sur des jetons .

Comment éviter ça? Un canal sécurisé comme HTTPS?

smwikipedia
la source
1
C'est pourquoi les jetons ne sont souvent valables que pour une courte période. Et oui, vous devez utiliser HTTPS si vous êtes préoccupé par la confidentialité de vos données.
Jonathon Reinhart
4
@JonathonReinhart Mais si un jeton expire bientôt, mon client devra obtenir un nouveau jeton en se réauthentifiant de temps en temps. N'est-ce pas un peu fastidieux?
smwikipedia
@JonathonReinhart Je pense que je comprends pourquoi le jeton est de courte durée. Parce que de cette façon, le serveur n'a pas besoin de garder une trace de l'expiration d'un jeton et donc de laisser la place à l'évolutivité. C'est un peu trade-offentre having finer control of token expirationet having better scalability.
smwikipedia
2
Cela peut-il aussi aider? - "Un mécanisme de sécurité commun pour détecter le vol de jeton consiste à garder une trace des origines de l'adresse IP de la demande." - décrit en détail dans la dernière section ici - firebase.google.com/docs/auth/admin/manage-sessions
Ula
3
Théoriquement, il est impossible d'empêcher le vol de jetons. Le mieux que nous puissions faire est de détecter que cela s'est produit, puis de révoquer la session dès que possible. La meilleure méthode de détection consiste à utiliser des jetons de rafraîchissement rotatifs (comme suggéré par la RFC 6819). Voici un blog qui explique cela en détail: supertokens.io/blog/…
Rishabh Poddar

Réponses:

284

Je suis l'auteur d'une bibliothèque de nœuds qui gère l'authentification dans une certaine profondeur, express-stormpath , donc je vais apporter des informations ici.

Tout d'abord, les JWT ne sont généralement PAS cryptés. Bien qu'il existe un moyen de chiffrer les JWT (voir: JWE ), ce n'est pas très courant dans la pratique pour de nombreuses raisons.

Ensuite, toute forme d'authentification (utilisant ou non des JWT) est soumise à des attaques MitM (man-in-the-middle). Ces attaques se produisent lorsqu'un attaquant peut CONSULTER le trafic DE VOTRE RÉSEAU lorsque vous effectuez des requêtes sur Internet. C'est ce que peut voir votre FAI, la NSA, etc.

C'est ce que SSL aide à éviter: en chiffrant le trafic RÉSEAU de votre ordinateur -> un serveur lors de l'authentification, un tiers qui surveille votre trafic réseau NE peut PAS voir vos jetons, mots de passe ou quoi que ce soit à moins qu'ils ne soient en mesure de le faire pour obtenir une copie de la clé SSL privée du serveur (peu probable). C'est la raison pour laquelle SSL est OBLIGATOIRE pour toutes les formes d'authentification.

Disons cependant que quelqu'un est en mesure d'exploiter votre SSL et est en mesure d'afficher votre jeton: la réponse à votre question est que OUI , l'attaquant sera en mesure d'utiliser ce jeton pour usurper votre identité et faire des demandes à votre serveur.

Maintenant, c'est là qu'interviennent les protocoles.

Les JWT ne sont qu'un standard pour un jeton d'authentification. Ils peuvent être utilisés pour à peu près n'importe quoi. La raison pour laquelle les JWT sont plutôt cool est que vous pouvez y incorporer des informations supplémentaires, et vous pouvez valider que personne ne les a gâchées (signature).

TOUTEFOIS, les JWT eux-mêmes n'ont rien à voir avec la «sécurité». À toutes fins utiles, les JWT sont plus ou moins la même chose que les clés API: juste des chaînes aléatoires que vous utilisez pour vous authentifier auprès d'un serveur quelque part.

Ce qui rend votre question plus intéressante, c'est le protocole utilisé (très probablement OAuth2).

La façon dont OAuth2 fonctionne est qu'il a été conçu pour donner aux clients des jetons TEMPORAIRES (comme les JWT!) Pour l'authentification pour une COURTE PÉRIODE DE TEMPS SEULEMENT!

L'idée est que si votre jeton est volé, l'attaquant ne peut l'utiliser que pendant une courte période.

Avec OAuth2, vous devez vous réauthentifier de temps en temps avec le serveur en fournissant votre nom d'utilisateur / mot de passe OU les informations d'identification de l'API, puis en récupérant un jeton en échange.

Parce que ce processus se produit de temps en temps, vos jetons changent fréquemment, ce qui rend plus difficile pour les attaquants de vous imiter constamment sans avoir de gros ennuis.

J'espère que cela aide ^^

rdegges
la source
3
L'auteur de l'article suivant fait valoir qu'un inconvénient de JWT est que le seul moyen de récupérer d'un JWT volé est de générer une nouvelle paire de clés et de déconnecter efficacement tous les utilisateurs. Alors qu'avec les identifiants de session stockés dans une base de données, le site Web pouvait supprimer uniquement les sessions de l'utilisateur affecté et le déconnecter de tous les appareils. Je ne sais pas comment OAuth2 s'inscrit dans l'image ici ou si cela aide à atténuer les inconvénients présentés. medium.com/@rahulgolwalkar/…
Marcel
4
L'auteur est incorrect. Il existe différents modèles de conception que vous pouvez utiliser pour invalider les jetons. Mais en général: l'utilisation d'un JWT pour tout type de but d'authentification est une mauvaise idée. Il est beaucoup plus efficace d'utiliser un cookie de session avec une idée de session intégrée à l'intérieur qui est signée cryptographiquement.
rdegges
1
@rdegges s'il vous plaît dites-moi comment JWT est une mauvaise idée pour l'authentification? et comment puis-je utiliser le cookie de session que vous avez mentionné dans votre commentaire ci-dessus?
noman tufail
6
C'est trop long pour taper une seule réponse. Si vous voulez en savoir plus, j'ai donné un exposé détaillé sur le sujet. Vous pouvez consulter mes diapositives en ligne: speakerdeck.com/rdegges/jwts-suck-and-are-stupid
rdegges
2
Théoriquement, il est impossible d'empêcher le vol de jetons. Le mieux que nous puissions faire est de détecter que cela s'est produit, puis de révoquer la session dès que possible. La meilleure méthode de détection consiste à utiliser des jetons de rafraîchissement rotatifs (comme suggéré par la RFC 6819). Voici un blog qui explique cela en détail: supertokens.io/blog/…
Rishabh Poddar
31

Je sais que c'est une vieille question mais je pense que je peux laisser tomber mes 0,50 $ ici, probablement quelqu'un peut améliorer ou fournir un argument pour décliner totalement mon approche. J'utilise des JWT dans une API RESTful sur HTTPS (ofc).

Pour que cela fonctionne, vous devez toujours émettre des jetons de courte durée (cela dépend de la plupart des cas, dans mon application, je règle la exprevendication à 30 minutes et ttlà 3 jours, afin que vous puissiez actualiser ce jeton tant qu'il ttlest toujours valide et le jeton n'a pas été mis sur liste noire )

Pour le authentication service, afin d'invalider les jetons, j'aime utiliser une couche de cache en mémoire ( redis dans mon cas) comme un JWT blacklist/ ban-listen face, en fonction de certains critères: (je sais que cela rompt avec la philosophie RESTful, mais les documents stockés sont vraiment de courte durée, comme je liste noire pour leur durée de vie restante - ttlrevendication-)

Remarque: les jetons sur liste noire ne peuvent pas être actualisés automatiquement

  • Si user.passwordou user.emaila été mis à jour (nécessite la confirmation du mot de passe), le service d'authentification renvoie un jeton actualisé et invalide (liste noire) les précédents, donc si votre client détecte que l'identité de l'utilisateur a été compromise d'une manière ou d'une autre, vous pouvez demander à cet utilisateur de changer son mot de passe . Si vous ne souhaitez pas utiliser la liste noire pour cela, vous pouvez (mais je ne vous encourage pas à) valider le champ ( iatémis à) de la revendication user.updated_at(si jwt.iat < user.updated_atJWT n'est pas valide).
  • L'utilisateur s'est délibérément déconnecté.

Enfin, vous validez le jeton normalement comme tout le monde.

Remarque 2: au lieu d'utiliser le jeton lui-même (qui est vraiment long) comme clé du cache, je suggère de générer et d'utiliser un jeton UUID pour la jtirevendication. Ce qui est bien et je pense (je ne suis pas sûr car cela vient à l'esprit) que vous pouvez également utiliser ce même UUID que le jeton CSRF, en renvoyant un secure/ non-http-onlycookie avec lui et en implémentant correctement l'en- X-XSRF-TOKENtête à l'aide de js. De cette façon, vous évitez le travail informatique de création d'un autre jeton pour les contrôles CSRF.

Frondor
la source
9
Il n'est jamais trop tard pour apporter votre idée. Merci pour votre réponse.
smwikipedia
2
Si vous stockez une liste noire sur le serveur qui doit être vérifiée pour chaque demande, pourquoi ne pas simplement utiliser une ancienne session ordinaire?
Franklin Yu
@FranklinYu Une liste noire est bien "moins chère" qu'une boutique de session complète. Puisque vous stockez des objets de valeur-clé de courte durée (en fonction de leur durée de vie restante, qui devrait être assez courte), et cela ne se produit que pour les actions de déconnexion et les actions qui invalident les jetons, donc tous les jetons ne sont pas ofc stocké.
Frondor
2
Comment peut-il être bon marché? Tout d'abord, si vous stockez toujours quelque chose du côté serveur, vous ne bénéficiez pas de l'avantage «d'évolutivité» revendiqué par JWT car il existe toujours un serveur central de liste noire avec lequel tout le serveur d'applications doit parler avant de faire quoi que ce soit. Si vous n'avez besoin de stocker qu'une liste noire de 1k en raison d'une expiration rapide, vous pouvez faire de même pour les sessions et par conséquent ne devez stocker que des sessions de 1k.
Franklin Yu
3
J'aime cette approche. Vous n'avez pas réellement à vérifier la liste noire sur chaque demande, uniquement sur une demande qui se produit après l'expiration du JWT (que vous pouvez lire à partir du jeton lui-même) et jusqu'à la période TTL après. Dans un cas d'utilisation "standard", cela devrait se produire, au plus, une fois dans la durée de vie d'un jeton donné. Une fois actualisé, vous pouvez probablement refuser toute future demande de rafraîchissement. Merci @Frondor
John Ackerman
7

Désolé d'être un peu en retard à ce sujet, mais j'avais les mêmes préoccupations et je veux maintenant contribuer quelque chose.

1) rdegges a ajouté un excellent point, que JWT n'a rien à voir avec la "sécurité" et valide simplement, si quelqu'un a foiré la charge utile ou non (signature); ssl aide à prévenir les violations.

2) Maintenant, si SSL est également compromis d'une manière ou d'une autre, tout espion peut voler notre jeton de porteur (JWT) et usurper l'identité de l'utilisateur authentique, une étape de niveau supérieure ce qui peut être fait est de rechercher la "preuve de possession" de JWT auprès du client. .

3) Maintenant, avec cette approche, le présentateur du JWT possède une clé de preuve de possession (POP) particulière, que le destinataire peut confirmer cryptographiquement si la demande provient du même utilisateur authentique ou non.

Pour cela, j'ai référé un article sur la preuve de possession et je suis convaincu par l'approche.

Je serai ravi, si je peux apporter quelque chose.

Santé (y)

yanky_cranky
la source
0

Ne pouvons-nous pas simplement ajouter l'ip de l'hôte initial qui a demandé de générer ce jeton JWT dans le cadre de la revendication? Maintenant, lorsque le JWT est volé et utilisé sur une autre machine, lorsque le serveur valide ce jeton, nous pouvons vérifier si l'IP de la machine demandée correspond à celle définie dans le cadre de la revendication. Cela ne correspondrait pas et le jeton peut donc être rejeté. De plus, si l'utilisateur essaie de manipuler le jeton en définissant sa propre ip sur le jeton, le jeton sera rejeté car le jeton est modifié.

Venkatesh Vs
la source
C'est une solution possible, mais pour les clients derrière un pare-feu, il est typique qu'une adresse IP soit choisie dans un pool d'adresses et cela peut changer à tout moment.
SpeedOfSpin