Le jeton d'authenticité est utilisé pour empêcher les attaques de type Cross-Site Request Forgery (CSRF). Pour comprendre le jeton d'authenticité, vous devez d'abord comprendre les attaques CSRF.
CSRF
Supposons que vous êtes l'auteur de bank.com
. Vous avez un formulaire sur votre site qui est utilisé pour transférer de l'argent vers un autre compte avec une demande GET:
Un pirate pourrait simplement envoyer une requête HTTP au serveur en disant GET /transfer?amount=$1000000&account-to=999999
, non?
Faux. L'attaque des pirates ne fonctionnera pas. Le serveur va penser essentiellement?
Hein? Qui est ce type qui essaie de lancer 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 session_id
cookie authentifiant le demandeur.
Lorsque vous vous connectez avec votre nom d'utilisateur et votre mot de passe, le serveur place un session_id
cookie 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 session_id
cookie, le serveur sait:
Oh, c'est John Doe. Il s'est connecté avec succès il y a 2,5 minutes. Il est prêt à partir.
Un pirate pourrait penser:
Hmm. Une requête HTTP normale ne fonctionnera pas, mais si je pouvais mettre la main sur ce session_id
cookie, je serais en or.
Le navigateur des utilisateurs dispose d'un ensemble de cookies pour le bank.com
domaine. Chaque fois que l'utilisateur fait une demande au bank.com
domaine, tous les cookies sont envoyés. Y compris le session_id
cookie.
Donc, si un pirate pouvait vous demander de faire la demande GET qui transfère de l'argent sur son compte, il réussirait. Comment pourrait-il vous inciter à le faire? Avec la contrefaçon de demande intersite.
C'est assez simple, en fait. Le pirate pourrait simplement 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 des utilisateurs rencontre cette balise d'image, il fera une demande GET à cette URL. Et puisque la demande provient de son navigateur, elle enverra avec elle tous les cookies associés bank.com
. Si l'utilisateur s'était récemment connecté à bank.com
... le session_id
cookie sera installé, et le serveur pensera que l'utilisateur voulait transférer 1 000 000 $ sur le compte 999999!
Eh bien, ne visitez pas de sites dangereux et tout ira bien.
Ce n'est pas suffisant. Et si quelqu'un poste cette image sur Facebook et qu'elle apparaît sur votre mur? Que se passe-t-il s'il est injecté dans un site que vous visitez avec 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é dynamiquement. Voici l'exemple du 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é
Lorsque vous avez ApplicationController
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="✓" />
<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 sûre.
Comment un attaquant est-il censé savoir ce qu'est ce jeton? Une valeur différente est générée aléatoirement à chaque génération du formulaire:
Une attaque Cross Site Scripting (XSS) - c'est comme ça. Mais c'est une vulnérabilité différente pour un jour différent.