web-dev-qa-db-fra.com

Compréhension du jeton d'authenticité Rails

Je rencontre des problèmes concernant le jeton d'authenticité dans Rails, comme je l'ai souvent fait maintenant.

Mais je ne veux vraiment pas simplement résoudre ce problème et continuer. J'aimerais vraiment comprendre le jeton Authenticité. Ma question est la suivante: avez-vous une source complète d’informations sur ce sujet ou passeriez-vous votre temps à expliquer en détail ici?

944
Ricardo Acras

Que se passe-t-il

Lorsque l'utilisateur visualise un formulaire pour créer, mettre à jour ou détruire une ressource, l'application Rails crée un authenticity_token aléatoire, stocke ce jeton dans la session et le place dans un champ masqué de la fenêtre. forme. Lorsque l'utilisateur soumet le formulaire, Rails cherche le authenticity_token, le compare à celui stocké dans la session et, s'ils correspondent, la demande est autorisée à continuer.

Pourquoi cela se produit

Comme 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 consulter le formulaire au sein de cette application. Imaginez que vous utilisez le service A, vous vous êtes connecté au service et tout va bien. Maintenant, imaginez que vous utilisiez le service B, que vous voyiez une photo qui vous plaisait et que vous appuyiez sur la photo pour l'agrandir. Maintenant, si du code malveillant existait au service B, il pourrait envoyer une demande au service A (auquel vous êtes connecté) et demander de supprimer votre compte en envoyant une demande à http://serviceA.com/close_account. C'est ce qu'on appelle CSRF (falsification de requête intersite) .

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

API docs décrit 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é par défaut pour les nouvelles applications Rails. Le paramètre de jeton est nommé authenticity_token par défaut. Le nom et la valeur de ce jeton doivent être ajoutés à chaque mise en forme générant des formulaires en incluant csrf_meta_tags dans l'en-tête HTML.

Notes

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? parce que la spécification HTTP indique que les requêtes GET sont idempotentes et qu'elles 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 véritable implémentation 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 pas non plus et ne stocke pas un 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 .

Leçons

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


EDIT: Vérifiez le commentaire de @erturne concernant les demandes GET étant idempotentes. Il l'explique mieux que moi.

1425
Faisal

Le jeton d'authenticité est conçu pour que vous sachiez que votre formulaire est soumis à partir de votre site Web. Il est généré à partir de la machine sur laquelle il s'exécute avec un identifiant unique que seul votre ordinateur peut connaître, évitant ainsi les attaques par falsification de requêtes entre sites.

Si vous rencontrez simplement des difficultés avec Rails refusant votre accès au script AJAX, vous pouvez utiliser

<%= form_authenticity_token %>

générer le bon jeton lors de la création de votre formulaire.

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

134
Topher Fangio

Qu'est ce que le CSRF?

Le jeton d'authenticité est une contre-mesure à la falsification de demande intersite (CSRF). Qu'est-ce que CSRF, demandez-vous?

C'est une façon pour un attaquant de potentiellement pirater des sessions sans même connaître les jetons de session.

scénario:

  • Visitez le site de votre banque, connectez-vous.
  • Rendez-vous ensuite sur le site de l'attaquant (par exemple, une annonce sponsorisée provenant d'une organisation non fiable).
  • La page de l'attaquant inclut un formulaire avec les mêmes champs que le formulaire "Transférer des fonds" de la banque.
  • L'attaquant connaît les informations de votre compte et dispose de champs de formulaire pré-remplis pour transférer de l'argent de votre compte sur le compte de l'attaquant.
  • La page de l'attaquant inclut du Javascript qui soumet le formulaire à votre banque.
  • Lorsque le formulaire est soumis, le navigateur inclut vos cookies pour le site de la banque, y compris le jeton de session.
  • La banque transfère de l'argent sur le compte de l'attaquant.
  • Le formulaire peut se trouver dans un iframe invisible. Vous ne savez donc jamais que l'attaque a eu lieu.
  • C'est ce qu'on appelle une falsification de requête intersite (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 sous la forme d'un champ caché.
  • Le jeton doit être imprévisible (l'attaquant ne peut pas le deviner).
  • Le serveur fournit un jeton valide dans les formulaires dans ses pages.
  • Le serveur vérifie le jeton lors de la publication du formulaire et rejette les formulaires sans le jeton approprié.
  • Exemple de jeton: identifiant de session chiffré avec la clé secrète du serveur.
  • Rails génère automatiquement ces jetons: voir le champ de saisie authenticity_token dans chaque formulaire.
83
Rose Perrone

Exemple d'attaque minimale à éviter: CSRF

Sur mon site internet 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 par le biais de cookies de session, ceux-ci seraient envoyés et le transfert serait effectué sans même que vous le sachiez.

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

  • avec la réponse GET ayant renvoyé le formulaire, Rails envoie un très long paramètre caché aléatoire
  • lorsque le navigateur effectue la demande POST, il envoie le paramètre et le serveur ne l'accepte que s'il correspond.

Ainsi, 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 ne pouvais pas le deviner, car il s'agit d'un nombre aléatoire énorme.

Cette technique de prévention s'appelle Modèle de jeton de synchroniseur .

Politique de même origine

Mais que se passe-t-il si l'attaquant fait deux requêtes avec JavaScript, une pour lire le jeton et l'autre pour effectuer le transfert?

Le modèle de jeton de synchronisation ne suffit pas à empêcher cela!

C’est là que la politique de la même origine s’applique à la rescousse, comme je l’ai expliqué à: https://security.stackexchange.com/questions/8264/why-is-the-same-Origin-policy-so- important/72569 # 72569

Comment Rails envoie les jetons

Couvert à: Rails: Comment fonctionne csrf_meta_tag?

Fondamentalement:

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

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

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

Autres approches de prévention

La méthode Authenticity Token est la méthode de Rails consistant à prevent'attaques par falsification de requêtes intersites (CSRF ou XSRF)' .

En termes simples, il s'assure que les requêtes PUT/POST/DELETE (méthodes pouvant modifier le contenu) envoyées à votre application Web sont effectuées à partir du navigateur du client et non d'un tiers (un attaquant) qui: a accès à un cookie créé côté client.

37
andi

Le jeton d'authenticité est utilisé pour empêcher les attaques de type CSRF (Cross-Site Request Forgery). Pour comprendre le jeton d'authenticité, vous devez d'abord comprendre les attaques CSRF.

CSRF

Supposons que vous soyez l'auteur de _bank.com_. Sur votre site, vous avez un formulaire utilisé pour transférer de l'argent sur un compte différent avec une demande GET:

enter image description here

Un pirate informatique pourrait simplement envoyer une requête HTTP au serveur en indiquant _GET /transfer?amount=$1000000&account-to=999999_, non?

enter image description here

Faux. L'attaque des hackers ne fonctionnera pas. Le serveur va fondamentalement penser?

Hein? Qui est ce gars qui essaie d'initier un transfert? Ce n'est pas le propriétaire du compte, c'est sûr.

Comment le serveur sait-il cela? Parce qu'il n'y a pas de cookie _session_id_ authentifiant le demandeur.

Lorsque vous vous connectez avec votre nom d'utilisateur et votre mot de passe, le serveur définit un cookie _session_id_ sur votre navigateur. De cette façon, vous n'avez pas à authentifier chaque demande avec votre nom d'utilisateur et votre mot de passe. Lorsque votre navigateur envoie le cookie _session_id_, le serveur sait:

Oh, c'est John Doe. Il s'est connecté avec succès il y a 2,5 minutes. Il est bon d'y aller.

Un pirate informatique pourrait penser:

Hmm. Une requête HTTP normale ne fonctionnera pas, mais si je pouvais mettre la main sur ce cookie _session_id_, je serais en or.

Le navigateur de l'utilisateur contient de nombreux cookies pour le domaine _bank.com_. Tous les cookies sont envoyés chaque fois que l'utilisateur adresse une demande au domaine _bank.com_. Y compris le cookie _session_id_.

Donc, si un pirate pouvait obtenir vous de faire la demande GET qui transfère de l'argent sur son compte, il aurait gain de cause. Comment pourrait-il vous inciter à le faire? Avec falsification de demande intersite.

C'est assez simple, en fait. Le pirate informatique pourrait vous faire visiter son site Web. Sur son site Web, il pourrait avoir la balise d'image suivante:

_<img src="http://bank.com/transfer?amount=$1000000&account-to=999999">
_

Lorsque le navigateur de l'utilisateur rencontre cette balise d'image, il envoie une requête GET à cette URL. Et puisque la demande provient de son navigateur, il enverra tous les cookies associés à _bank.com_. Si l'utilisateur s'est récemment connecté à _bank.com_, le cookie _session_id_ sera défini et le serveur pensera que l'utilisateur souhaitait transférer 1 000 000 USD sur le compte 999999!

enter image description here

Eh bien, ne visitez pas de sites dangereux et tout ira bien.

Cela ne suffit pas. Et si quelqu'un publiait cette image sur Facebook et que celle-ci apparaisse sur votre mur? Que se passe-t-il s'il est injecté dans un site visité par une attaque XSS?

Ce n'est pas si grave. Seules les demandes GET sont vulnérables.

Pas vrai. Un formulaire qui envoie une demande POST peut être généré de manière dynamique. Voici l'exemple de Guide Rails sur la Sécurité :

_<a href="http://www.harmless.com/" onclick="
  var f = document.createElement('form');
  f.style.display = 'none';
  this.parentNode.appendChild(f);
  f.method = 'POST';
  f.action = 'http://www.example.com/account/destroy';
  f.submit();
  return false;">To the harmless survey</a>
_

Jeton d'authenticité

Quand votre ApplicationController a ceci:

_protect_from_forgery with: :exception
_

Cette:

_<%= form_tag do %>
  Form contents
<% end %>
_

Est compilé dans ceci:

_<form accept-charset="UTF-8" action="/" method="post">
  <input name="utf8" type="hidden" value="&#x2713;" />
  <input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />
  Form contents
</form>
_

En particulier, les éléments suivants sont générés:

_<input name="authenticity_token" type="hidden" value="J7CBxfHalt49OSHp27hblqK20c9PgwJ108nDHX/8Cts=" />
_

Pour se protéger contre les attaques CSRF, si Rails ne voit pas le jeton d'authenticité envoyé avec une demande, il ne considérera pas la demande comme étant sûre.

Comment un attaquant est-il supposé savoir ce qu'est ce jeton? Une valeur différente est générée aléatoirement à chaque génération du formulaire:

enter image description here

Une attaque XSS (Cross Site Scripting) - voilà comment. Mais c'est une vulnérabilité différente pour un autre jour.

37
Adam Zerner

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

33
Yuan He

Attention, le mécanisme de jeton d'authenticité peut entraîner des conditions de concurrence si vous avez plusieurs demandes simultanées du même client. Dans cette situation, votre serveur peut générer plusieurs jetons d'authenticité lorsqu'il ne devrait y en avoir qu'un, et le client recevant le jeton précédent dans un formulaire échouera lors de la prochaine requête car le jeton de cookie de session a été écrasé. Il existe une description de ce problème et une solution pas tout à fait triviale ici: http://www.paulbutcher.com/2007/05/race-conditions-in-Rails-sessions-and-how-tow-to-) corrigez-les /

26
jdp

Méthodes où authenticity_token est requis

authenticity_token est requis dans le cas de méthodes idempotentes telles que post, put et delete, car les méthodes Idempotent affectent les données.

Pourquoi est-il nécessaire

Il est nécessaire d'empêcher les mauvaises actions. authenticity_token est stocké en session, chaque fois qu'un formulaire est créé sur des pages Web pour créer ou mettre à jour des ressources, un jeton d'authenticité est stocké dans un champ caché et envoyé avec le formulaire sur le serveur. Avant d'exécuter l'action, authenticity_token envoyé par l'utilisateur est vérifié avec authenticity_token enregistré dans la session. Si authenticity_token est identique, le processus est poursuivi, sinon il ne réalise aucune action.

9
uma

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 à partir de la page de l'application, et non d'une autre application ou site.

Pourquoi un authentication_token est-il nécessaire?

Pour protéger votre application ou votre site contre la falsification de requêtes entre sites.

Comment ajouter un authentication_token à un formulaire?

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

4
Pradeep Sapkota