web-dev-qa-db-fra.com

Puis-je empêcher une attaque par rejeu de mes JWT signés?

J'ai implémenté une authentification sans état sur HTTP dans Laravel, en utilisant des JWT.

  1. J'envoie mon nom d'utilisateur/mot de passe depuis le frontend.
  2. Le serveur authentifie l'utilisateur, renvoie un JWT signé avec une date d'expiration.
    • J'utilise l'algorithme HS512 pour signer avec une clé privée (uniquement disponible sur le serveur).
  3. Frontend stocke le jeton pour les demandes futures.
  4. Le frontend envoie la prochaine requête avec le jeton inclus.
  5. Le serveur vérifie que le jeton est valide et non expiré et laisse l'action se poursuivre si oui aux deux.
  6. Lorsque le jeton expire, le serveur envoie un message de "déconnexion".

Toutes ces communications se font via HTTPS.

Je peux donc voir que cela est sécurisé à partir de ces points:

  • Les attaquants ne peuvent pas renifler le trafic et voler le jeton JWT à cause de HTTPS.
  • Les attaquants ne peuvent pas générer et envoyer de jeton impair car le serveur vérifie la signature à l'aide de sa clé privée.
  • Les attaquants ne peuvent pas modifier l'utilisateur (et donc le rôle + les autorisations du demandeur) qui effectue la demande, car cela fait partie de la revendication sub dans le jeton.

Mais, j'ai deux questions:

  1. Que faire s'il y a un virus sur l'ordinateur ou le mobile de l'utilisateur et qu'il a volé un jeton valide de RAM ou du navigateur. Il peut alors envoyer plus de demandes et elles seront acceptées. Existe-t-il aucun moyen de se protéger contre cela?
  2. Y a-t-il une autre façon d'attaquer ce système que je ne vois pas?
30
Aditya M P

La revendication jti telle que décrite ici est un mécanisme facultatif pour empêcher de nouvelles attaques de relecture. De la spécification:

4.1.7. Allégation "jti" (ID JWT)

La revendication "jti" (ID JWT) fournit un identifiant unique pour le JWT. La valeur d'identifiant DOIT être attribuée de manière à garantir qu'il y a une probabilité négligeable que la même valeur soit accidentellement attribuée à un autre objet de données; si l'application utilise plusieurs émetteurs, les collisions DOIVENT également être évitées entre les valeurs produites par différents émetteurs. La revendication "jti" peut être utilisée pour empêcher la relecture du JWT. La valeur "jti" est une chaîne sensible à la casse. L'utilisation de cette réclamation est FACULTATIVE.

En fin de compte, cela rend votre serveur avec état, mais cela empêche les rediffusions illimitées si vous détectez un comportement anormal ou si un utilisateur signale une activité suspecte. Considérez le scénario suivant.

  1. Un utilisateur se connecte. Votre serveur génère un JWT et stocke la signature ainsi que certaines métadonnées (l'ID utilisateur et le type de client effectuant la demande, peut-être, et le jti).
  2. L'utilisateur signale un comportement suspect.
  3. L'application "déconnecte" l'utilisateur de tous les appareils en supprimant tous les JWT dans le magasin principal attaché à cet utilisateur. Maintenant, l'application peut dire "Je sais que vous avez une signature valide, mais je ne l'accepte pas parce que je ne l'ai pas créée."
    • Si vos métadonnées sont suffisamment précises, vous pouvez utiliser le jti plus des informations supplémentaires pour, disons, ne déconnecter l'utilisateur que des appareils donnés.

Comme mentionné ci-dessus, cela rend inévitablement votre serveur avec état. Cela n'empêche pas non plus carrément les attaques de réexécution, mais il peut arrêter de telles attaques après qu'une détection ait été détectée.

Une méthode alternative/supplémentaire PEUT carrément empêcher les attaques par rejeu dans une certaine mesure, au risque de gêner potentiellement l'utilisateur. Faites en sorte que l'adresse IP de l'utilisateur fasse partie de la revendication ET des métadonnées stockées lors de la connexion et validez que l'IP utilisant le JWT est celle que vous attendez. Cela peut être frustrant pour un utilisateur qui dit travailler à la maison et dans un café, mais cela peut être une exigence acceptable pour les applications de haute sécurité.

23
bretmattingly

S'il y a du code qui s'exécute dans le même contexte de votre application Web, qu'il fasse partie d'une attaque XSS dans le navigateur ou d'un malware/virus sur la machine des utilisateurs, il serait difficile (impossible?) De différencier ces demandes de votre posséder.

Si l'attaquant a accès à l'ordinateur, il pourrait également simplement voler les données de vos applications aux requêtes normales de votre serveur.

Potentiellement, vous pouvez effectuer une analyse du style de détection d'intrusion côté serveur: par exemple vérifier le nombre élevé de demandes ou le nombre d'articles; appliquer un schéma de référence personnalisé dans lequel vous savez quels composants de votre application Web font des demandes de données. Peut-être alors déclencher une nouvelle authentification lorsque vous détecterez un comportement anormal? Vous auriez également besoin d'un moyen côté serveur pour expirer votre JWT au-dessus du exp intégré dans le JWT.

4
Kevin Hakanson

Pourquoi ne pas avoir une date-heure comme charge utile et expiration? Vous n'avez pas besoin de modifier la charge utile et la logique d'application peut expirer le jeton. Ou utilisez un nouveau secret basé sur une nature de feuille (semblable à DUKPT ) afin qu'une nouvelle demande de jeton invalide l'ancienne.

1
TheBB