J'écris une application (Django, ça arrive) et je veux juste une idée de ce qu'est réellement un "token CSRF" et comment il protège les données. Les données de publication ne sont-elles pas sûres si vous n'utilisez pas de jetons CSRF?
J'écris une application (Django, ça arrive) et je veux juste une idée de ce qu'est réellement un "token CSRF" et comment il protège les données. Les données de publication ne sont-elles pas sûres si vous n'utilisez pas de jetons CSRF?
Réponses:
www.mybank.com
mybank.com
entraînera une demande (conceptuelle) du formulaire http://www.mybank.com/transfer?to=<SomeAccountnumber>;amount=<SomeAmount>
. (Votre numéro de compte n'est pas nécessaire, car il est impliqué par votre connexion.)www.cute-cat-pictures.org
, sans savoir qu'il s'agit d'un site malveillant.mybank.com
(nécessite un peu de chance!), Il pourrait inclure sur sa page une demande comme http://www.mybank.com/transfer?to=123456;amount=10000
(où 123456
est le numéro de son compte aux îles Caïmans) et 10000
est un montant que vous pensiez auparavant être heureux de posséder).www.cute-cat-pictures.org
page, donc votre navigateur fera cette demande.www.mybank.com
cookie et elle semblera parfaitement légitime. Voilà votre argent!C'est le monde sans jetons CSRF .
Maintenant, pour le meilleur avec les jetons CSRF :
http://www.mybank.com/transfer?to=123456;amount=10000;token=31415926535897932384626433832795028841971
.mybank.com
sera inclus sur leur propre page Web lorsqu'ils vous le serviront. C'est différent chaque fois qu'ils servent une page à qui que ce soit.www.mybank.com
.Résultat: vous conservez vos 10000
unités monétaires. Je vous suggère d'en faire don à Wikipedia.
(Votre kilométrage peut varier.)
MODIFIER un commentaire qui mérite d'être lu:
Il serait intéressant de noter que le script de www.cute-cat-pictures.org
normalement n'a pas accès à votre jeton anti-CSRF à www.mybank.com
cause du contrôle d'accès HTTP. Cette note est importante pour certaines personnes qui envoient de manière déraisonnable un en-tête Access-Control-Allow-Origin: *
pour chaque réponse de site Web sans savoir à quoi elles servent, simplement parce qu'elles ne peuvent pas utiliser l'API d'un autre site Web.
www.cute-cat-pictures.org
normalement n'a pas accès à votre jeton anti-CSRF à www.mybank.com
cause du contrôle d'accès HTTP. Cette note est importante pour certaines personnes qui envoient de manière déraisonnable un en-tête Access-Control-Allow-Origin: *
pour chaque réponse de site Web sans savoir à quoi elles servent, simplement parce qu'elles ne peuvent pas utiliser l'API d'un autre site Web.
Oui, les données de publication sont en sécurité. Mais l'origine de ces données ne l'est pas. De cette façon, quelqu'un peut inciter un utilisateur avec JS à se connecter à votre site, tout en parcourant la page Web de l'attaquant.
Afin d'éviter cela, django enverra une clé aléatoire à la fois dans le cookie et les données du formulaire. Ensuite, lorsque les utilisateurs effectueront des POST, il vérifiera si deux clés sont identiques. Dans le cas où l'utilisateur est trompé, le site Web tiers ne peut pas obtenir les cookies de votre site, provoquant ainsi une erreur d'authentification.
Le site génère un jeton unique lorsqu'il crée la page de formulaire. Ce jeton est requis pour publier / récupérer des données sur le serveur.
Étant donné que le jeton est généré par votre site et fourni uniquement lorsque la page avec le formulaire est générée, certains autres sites ne peuvent pas imiter vos formulaires - ils n'auront pas le jeton et ne pourront donc pas publier sur votre site.
Le blog Cloud Under a une bonne explication des jetons CSRF.
Imaginez que vous disposiez d'un site Web comme un Twitter simplifié, hébergé sur a.com. Les utilisateurs connectés peuvent saisir du texte (un tweet) dans un formulaire qui est envoyé au serveur en tant que demande POST et publié lorsqu'ils cliquent sur le bouton Envoyer. Sur le serveur, l'utilisateur est identifié par un cookie contenant son identifiant de session unique, afin que votre serveur sache qui a posté le Tweet.
Le formulaire pourrait être aussi simple que cela:
<form action="http://a.com/tweet" method="POST"> <input type="text" name="tweet"> <input type="submit"> </form>
Imaginez maintenant qu'un méchant copie et colle ce formulaire sur son site Web malveillant, disons b.com. Le formulaire fonctionnerait toujours. Tant qu'un utilisateur est connecté à votre Twitter (c'est-à-dire qu'il a un cookie de session valide pour a.com), la demande POST sera envoyée
http://a.com/tweet
et traitée comme d'habitude lorsque l'utilisateur clique sur le bouton Soumettre.Jusqu'à présent, ce n'est pas un gros problème tant que l'utilisateur est informé de ce que fait exactement le formulaire, mais que se passe-t-il si notre méchant peaufine le formulaire comme ceci:
<form action="https://example.com/tweet" method="POST"> <input type="hidden" name="tweet" value="Buy great products at http://b.com/#iambad"> <input type="submit" value="Click to win!"> </form>
Maintenant, si l'un de vos utilisateurs se retrouve sur le site Web du méchant et clique sur "Cliquez pour gagner!" , le formulaire est soumis à votre site Web, l'utilisateur est correctement identifié par l'ID de session dans le cookie et le Tweet caché est publié.
Si notre méchant était encore pire, il obligerait l'utilisateur innocent à soumettre ce formulaire dès qu'il ouvrirait sa page Web en utilisant JavaScript, peut-être même complètement caché dans une iframe invisible. Il s'agit essentiellement d'une falsification de demande intersite.
Un formulaire peut être facilement envoyé de partout à partout. C'est généralement une caractéristique commune, mais il existe de nombreux autres cas où il est important de n'autoriser l'envoi d'un formulaire que depuis le domaine auquel il appartient.
Les choses sont encore pires si votre application Web ne fait pas de distinction entre les requêtes POST et GET (par exemple en PHP en utilisant $ _REQUEST au lieu de $ _POST). Ne fais pas ça! Les demandes de modification des données peuvent être soumises aussi facilement que
<img src="http://a.com/tweet?tweet=This+is+really+bad">
, intégrées dans un site Web malveillant ou même un e-mail.Comment puis-je m'assurer qu'un formulaire ne peut être soumis qu'à partir de mon propre site Web? C'est là qu'intervient le jeton CSRF. Un jeton CSRF est une chaîne aléatoire, difficile à deviner. Sur une page avec un formulaire que vous souhaitez protéger, le serveur générerait une chaîne aléatoire, le jeton CSRF, l'ajouterait au formulaire en tant que champ masqué et le mémoriserait en quelque sorte, soit en le stockant dans la session, soit en définissant un cookie contenant la valeur. Maintenant, le formulaire ressemblerait à ceci:
<form action="https://example.com/tweet" method="POST"> <input type="hidden" name="csrf-token" value="nc98P987bcpncYhoadjoiydc9ajDlcn"> <input type="text" name="tweet"> <input type="submit"> </form>
Lorsque l'utilisateur soumet le formulaire, le serveur doit simplement comparer la valeur du champ publié csrf-token (le nom n'a pas d'importance) avec le jeton CSRF mémorisé par le serveur. Si les deux chaînes sont égales, le serveur peut continuer à traiter le formulaire. Sinon, le serveur doit immédiatement arrêter de traiter le formulaire et répondre avec une erreur.
Pourquoi ça marche? Il y a plusieurs raisons pour lesquelles le méchant de notre exemple ci-dessus n'est pas en mesure d'obtenir le jeton CSRF:
La copie du code source statique de notre page vers un site Web différent serait inutile, car la valeur du champ caché change avec chaque utilisateur. Sans le site Web du méchant connaissant le jeton CSRF de l'utilisateur actuel, votre serveur rejetterait toujours la demande POST.
Parce que la page malveillante du méchant est chargée par le navigateur de votre utilisateur à partir d'un domaine différent (b.com au lieu de a.com), le méchant n'a aucune chance de coder un JavaScript, qui charge le contenu et donc le jeton CSRF actuel de notre utilisateur à partir de votre site web. En effet, les navigateurs Web n'autorisent pas les demandes AJAX interdomaines par défaut.
Le méchant n'est pas non plus en mesure d'accéder au cookie défini par votre serveur, car les domaines ne correspondraient pas.
Quand dois-je me protéger contre la contrefaçon de demande intersite? Si vous pouvez vous assurer de ne pas mélanger GET, POST et d'autres méthodes de demande comme décrit ci-dessus, un bon début serait de protéger toutes les demandes POST par défaut.
Vous n'avez pas à protéger les demandes PUT et DELETE, car comme expliqué ci-dessus, un formulaire HTML standard ne peut pas être soumis par un navigateur utilisant ces méthodes.
JavaScript d'autre part peut en effet faire d'autres types de demandes, par exemple en utilisant la fonction $ .ajax () de jQuery, mais n'oubliez pas que pour que les demandes AJAX fonctionnent, les domaines doivent correspondre (tant que vous ne configurez pas explicitement votre serveur Web autrement) .
Cela signifie que, souvent, vous n'avez même pas besoin d'ajouter un jeton CSRF aux demandes AJAX, même s'il s'agit de demandes POST, mais vous devrez vous assurer de ne contourner la vérification CSRF dans votre application Web que si la demande POST est en fait un Demande AJAX. Vous pouvez le faire en recherchant la présence d'un en-tête comme X-Requested-With, que les requêtes AJAX incluent généralement. Vous pouvez également définir un autre en-tête personnalisé et vérifier sa présence côté serveur. C'est sûr, car un navigateur n'ajoutera pas d'en-têtes personnalisés à une soumission de formulaire HTML régulière (voir ci-dessus), donc aucune chance pour M. Bad Guy de simuler ce comportement avec un formulaire.
Si vous avez un doute sur les demandes AJAX, car pour une raison quelconque, vous ne pouvez pas rechercher un en-tête comme X-Requested-With, passez simplement le jeton CSRF généré à votre JavaScript et ajoutez le jeton à la demande AJAX. Il existe plusieurs façons de procéder; soit l'ajouter à la charge utile comme le ferait un formulaire HTML normal, soit ajouter un en-tête personnalisé à la demande AJAX. Tant que votre serveur sait où le rechercher dans une demande entrante et est capable de le comparer à la valeur d'origine dont il se souvient de la session ou du cookie, vous êtes trié.
La racine de tout cela est de s'assurer que les demandes proviennent des utilisateurs réels du site. Un jeton csrf est généré pour les formulaires et doit être lié aux sessions de l'utilisateur. Il est utilisé pour envoyer des requêtes au serveur, dans lequel le jeton les valide. C'est une façon de se protéger contre csrf, une autre serait de vérifier l'en-tête du référent.