ruby-on-rails - authenticity - rails session




Comprendre le jeton d'authenticité Rails (7)

Qu'est-ce que CSRF?

Le jeton d'authenticité est une contre-mesure à la contrefaçon de demande inter-site (CSRF). Qu'est-ce que CSRF, demandez-vous?

C'est un moyen qu'un pirate peut potentiellement pirater des sessions sans même connaître les jetons de session.

Scénario

  • Visitez le site de votre banque, connectez-vous.
  • Ensuite, visitez le site de l'attaquant (par exemple, une annonce sponsorisée provenant d'une organisation non approuvée).
  • La page de l'attaquant inclut un formulaire avec les mêmes champs que le formulaire "Transfert de fonds" de la banque.
  • L'attaquant connaît vos informations de compte et a pré-rempli les champs de formulaire pour transférer de l'argent de votre compte vers le compte de l'attaquant.
  • La page de l'attaquant inclut Javascript qui soumet le formulaire à votre banque.
  • Lorsque le formulaire est envoyé, le navigateur inclut vos cookies pour le site de la banque, y compris le jeton de session.
  • La banque transfère de l'argent au compte de l'attaquant.
  • Le formulaire peut être dans un iframe invisible, donc vous ne savez jamais que l'attaque s'est produite.
  • C'est ce qu'on appelle Cross-Site Request Forgery (CSRF).

Solution CSRF :

  • Le serveur peut marquer des formulaires provenant du serveur lui-même
  • Chaque formulaire doit contenir un jeton d'authentification supplémentaire en tant que champ masqué.
  • Le jeton doit être imprévisible (l'attaquant ne peut pas le deviner).
  • Le serveur fournit un jeton valide dans les formulaires de ses pages.
  • Le serveur vérifie le jeton lorsqu'il est posté, rejette les formulaires sans jeton approprié.
  • Exemple de jeton: identifiant de session chiffré avec la clé secrète du serveur.
  • Rails génère automatiquement de tels jetons: consultez le champ de saisie authenticity_token sous chaque forme.

Je suis confronté à quelques problèmes concernant Authenticity Token in Rails, comme je l'ai plusieurs fois maintenant.

Mais je ne veux vraiment pas résoudre ce problème et continuer. J'aimerais vraiment comprendre le jeton Authenticité. Eh bien, ma question est, avez-vous une source complète d'informations sur ce sujet ou souhaitez-vous passer votre temps à expliquer dans les détails ici?


Ce qui se produit

Lorsque l'utilisateur affiche un formulaire pour créer, mettre à jour ou détruire une ressource, l'application Rails crée une authenticity_token aléatoire, stocke ce jeton dans la session et le place dans un champ masqué dans le formulaire. Lorsque l'utilisateur soumet le formulaire, Rails recherche l' authenticity_token , le compare à celui stocké dans la session et, s'il correspond, la requête est autorisée à continuer.

Pourquoi ça arrive

Puisque le jeton d'authenticité est stocké dans la session, le client ne peut pas connaître sa valeur. Cela empêche les utilisateurs de soumettre des formulaires à une application Rails sans afficher le formulaire dans cette application. Imaginez que vous utilisez le service A, vous vous êtes connecté au service et tout va bien. Maintenant, imaginez que vous êtes allé utiliser le service B, et vous avez vu une image que vous aimez, et appuyé sur l'image pour en voir une plus grande taille. Maintenant, si un code mal était là au service B, il peut envoyer une demande au service A (auquel vous êtes connecté), et demander à supprimer votre compte, en envoyant une demande à http://serviceA.com/close_account . C'est ce qu'on appelle CSRF (Cross Site Request Forgery) .

Si le service A utilise des jetons d'authenticité, ce vecteur d'attaque n'est plus applicable, car la demande du service B ne contiendra pas le bon jeton d'authenticité et ne sera pas autorisée à continuer.

Les documents API décrivent les détails de la balise META:

La protection CSRF est activée avec la méthode protect_from_forgery , qui vérifie le jeton et réinitialise la session si elle ne correspond pas à ce qui était attendu. Un appel à cette méthode est généré pour les nouvelles applications Rails par défaut. Le paramètre token est nommé authenticity_token par défaut. Le nom et la valeur de ce jeton doivent être ajoutés à chaque mise en page qui rend les formulaires en incluant csrf_meta_tags dans la tête HTML.

Remarques

Gardez à l'esprit que Rails ne vérifie que les méthodes non-idempotentes (POST, PUT / PATCH et DELETE). Les requêtes GET ne sont pas vérifiées pour le jeton d'authenticité. Pourquoi? car la spécification HTTP indique que les requêtes GET sont idempotentes et ne devraient pas créer, modifier ou détruire des ressources sur le serveur, et la requête devrait être idempotente (si vous exécutez la même commande plusieurs fois, vous devriez obtenir le même résultat à chaque fois).

De plus, la mise en œuvre réelle est un peu plus compliquée que celle définie au début, assurant une meilleure sécurité. Rails n'émet pas le même jeton stocké avec chaque formulaire. Il ne génère et ne stocke pas non plus de jeton différent à chaque fois. Il génère et stocke un hachage cryptographique dans une session et émet de nouveaux jetons cryptographiques, qui peuvent être comparés à ceux stockés, chaque fois qu'une page est rendue. Voir request_forgery_protection.rb .

Cours

Utilisez authenticity_token pour protéger vos méthodes non idempotentes (POST, PUT / PATCH et DELETE). Veillez également à ne pas autoriser les demandes GET susceptibles de modifier les ressources sur le serveur.

EDIT: Vérifiez le commentaire de @erturne concernant les requêtes GET idempotentes. Il l'explique mieux que moi ici.


Le Authenticity Token est la méthode des rails pour prevent les attaques par falsification de requête inter-site (CSRF ou XSRF) .

Pour faire simple, il s'assure que les requêtes PUT / POST / DELETE (méthodes pouvant modifier le contenu) de votre application web proviennent du navigateur du client et non d'un tiers (un attaquant) ayant accès à un cookie créé du côté client.


Le jeton d'authenticité est conçu pour que vous sachiez que votre formulaire est envoyé depuis votre site Web. Il est généré à partir de la machine sur laquelle il s'exécute avec un identifiant unique que seule votre machine peut connaître, ce qui permet d'éviter les attaques de falsification de requêtes intersites.

Si vous avez simplement des difficultés avec les rails qui refusent l'accès au script AJAX, vous pouvez utiliser

<%= form_authenticity_token %>

pour générer le jeton correct lorsque vous créez votre formulaire.

Vous pouvez en lire plus à ce sujet dans la documentation .


puisque Authenticity Token est si important, et dans Rails 3.0+, vous pouvez utiliser

 <%= token_tag nil %>

créer

<input name="authenticity_token" type="hidden" value="token_value">

nulle part


Exemple d'attaque minimale qui serait évitée

Sur mon site evil.com je vous convaincs de soumettre le formulaire suivant:

<form action="http://bank.com/transfer" method="post">
  <p><input type="hidden" name="to"      value="ciro"></p>
  <p><input type="hidden" name="ammount" value="100"></p>
  <p><button type="submit">CLICK TO GET PRIZE!!!</button></p>
</form>

Si vous êtes connecté à votre banque via des cookies de session, les cookies seront envoyés et le transfert sera effectué sans même que vous le sachiez.

C'est là que le jeton CSRF entre en jeu:

  • avec la réponse GET qui a renvoyé le formulaire, Rails envoie un paramètre caché aléatoire très long
  • lorsque le navigateur fait la requête POST, il envoie le paramètre et le serveur ne l'accepte que s'il correspond

Donc le formulaire sur un navigateur authentique ressemblerait à ceci:

<form action="http://bank.com/transfer" method="post">
  <p><input type="hidden" name="authenticity_token" value="j/DcoJ2VZvr7vdf8CHKsvjdlDbmiizaOb5B8DMALg6s=" ></p>
  <p><input type="hidden" name="to"                 value="ciro"></p>
  <p><input type="hidden" name="ammount"            value="100"></p>
  <p><button type="submit">Send 100$ to Ciro.</button></p>
</form>

Ainsi, mon attaque échouerait, car elle n'envoyait pas le paramètre authenticity_token , et je n'aurais jamais pu le deviner car c'est un nombre aléatoire énorme.

Cette technique de prévention est appelée Synchronizer Token Pattern .

Le modèle de jeton de synchroniseur fonctionne grâce à la même politique d'origine : si je pouvais faire une requête XHR GET à votre banque depuis evil.com , et lire le résultat, je serais capable de lire un jeton et de faire la demande plus tard. J'ai expliqué ceci plus loin à: https://security.stackexchange.com/a/72569/53321

Je vous recommande fortement de lire le guide OWASP , sur ceci et toute autre question de sécurité.

Comment Rails envoie les jetons

Couvert à: Rails: Comment fonctionne csrf_meta_tag?

Fondamentalement:

  • Les helpers HTML comme form_tag ajoutent un champ caché au formulaire pour vous si ce n'est pas un formulaire GET

  • AJAX est traité automatiquement par jquery-ujs , qui lit le jeton des meta éléments ajoutés à votre en-tête par csrf_meta_tags (présent dans le template par défaut), et l'ajoute à toute requête faite.

    uJS tente également de mettre à jour le jeton dans des formulaires dans des fragments mis en cache obsolètes.

Autres approches de prévention


Qu'est-ce qu'un authentication_token?

Il s'agit d'une chaîne aléatoire utilisée par l'application Rails pour s'assurer que l'utilisateur demande ou exécute une action depuis la page de l'application, et non depuis une autre application ou un autre site.

Pourquoi un authentication_token est-il nécessaire?

Pour protéger votre application ou votre site contre les falsifications de requêtes intersites.

Comment ajouter un authentication_token à un formulaire?

Si vous générez un formulaire en utilisant form_for tag, un identificateur authentication_token est automatiquement ajouté sinon vous pouvez utiliser <%= csrf_meta_tag %> .





authenticity-token