J'essaie de comprendre tout le problème du CSRF et les moyens appropriés de le prévenir. (Ressources que j'ai lues, comprises et approuvées: Aide-mémoire sur la prévention de la CSRF de l'OWASP , Questions sur la CSRF .)
Si je comprends bien, la vulnérabilité autour de CSRF est introduite par l'hypothèse que (du point de vue du serveur Web) un cookie de session valide dans une requête HTTP entrante reflète les souhaits d'un utilisateur authentifié. Mais tous les cookies du domaine d'origine sont magiquement attachés à la demande par le navigateur, donc tout ce que le serveur peut inférer de la présence d'un cookie de session valide dans une demande est que la demande provient d'un navigateur qui a une session authentifiée; il ne peut plus rien supposer du codeen cours d'exécution dans ce navigateur, ou s'il reflète vraiment les souhaits des utilisateurs. Le moyen d'empêcher cela est d'inclure des informations d'authentification supplémentaires (le "jeton CSRF") dans la demande, véhiculées par un autre moyen que la gestion automatique des cookies du navigateur. En gros, le cookie de session authentifie l'utilisateur / navigateur et le jeton CSRF authentifie le code exécuté dans le navigateur.
Donc, en résumé, si vous utilisez un cookie de session pour authentifier les utilisateurs de votre application Web, vous devez également ajouter un jeton CSRF à chaque réponse et exiger un jeton CSRF correspondant dans chaque demande (de mutation). Le jeton CSRF effectue ensuite un aller-retour du serveur au navigateur pour revenir au serveur, prouvant au serveur que la page faisant la demande est approuvée par (générée par, même) ce serveur.
Passons à ma question, qui concerne la méthode de transport spécifique utilisée pour ce jeton CSRF lors de cet aller-retour.
Il semble courant (par exemple dans AngularJS , Django , Rails ) d'envoyer le jeton CSRF du serveur au client sous forme de cookie (c'est-à-dire dans un en-tête Set-Cookie), puis de laisser Javascript dans le client le gratter du cookie et le joindre en tant qu'en-tête XSRF-TOKEN distinct à renvoyer au serveur.
(Une autre méthode est celle recommandée par exemple par Express , où le jeton CSRF généré par le serveur est inclus dans le corps de la réponse via l'expansion du modèle côté serveur, attaché directement au code / balisage qui le fournira au serveur, par exemple en tant qu'entrée de formulaire masquée. Cet exemple est une façon de faire plus Web 1.0, mais généraliserait bien à un client plus lourd en JS.)
Pourquoi est-il si courant d'utiliser Set-Cookie comme transport en aval pour le jeton CSRF / pourquoi est-ce une bonne idée? J'imagine que les auteurs de tous ces cadres ont soigneusement examiné leurs options et ne se sont pas trompés. Mais à première vue, l'utilisation de cookies pour contourner ce qui est essentiellement une limitation de conception des cookies semble idiote. En fait, si vous utilisiez des cookies comme transport aller-retour (Set-Cookie: en-tête en aval pour que le serveur indique au navigateur le token CSRF, et Cookie: en-tête en amont pour que le navigateur le retourne au serveur), vous réintroduiriez la vulnérabilité que vous essaient de réparer.
Je me rends compte que les cadres ci-dessus n'utilisent pas de cookies pour l'ensemble du trajet aller-retour pour le jeton CSRF; ils utilisent Set-Cookie en aval, puis quelque chose d'autre (par exemple un en-tête X-CSRF-Token) en amont, et cela ferme la vulnérabilité. Mais même utiliser Set-Cookie comme transport en aval est potentiellement trompeur et dangereux; le navigateur attachera maintenant le jeton CSRF à chaque demande, y compris les demandes XSRF malveillantes authentiques; au mieux, cela rend la demande plus importante qu'elle ne devrait l'être et au pire, un morceau de code de serveur bien intentionné mais mal orienté pourrait en fait essayer de l'utiliser, ce qui serait vraiment mauvais. De plus, étant donné que le destinataire prévu du jeton CSRF est le Javascript côté client, cela signifie que ce cookie ne peut pas être protégé avec http uniquement.
Réponses:
Une bonne raison, que vous avez en quelque sorte abordée, est qu'une fois que le cookie CSRF a été reçu, il est ensuite disponible pour une utilisation dans toute l'application dans le script client pour une utilisation à la fois dans les formulaires réguliers et les POST AJAX. Cela aura du sens dans une application JavaScript lourde telle que celle employée par AngularJS (l'utilisation d'AngularJS ne nécessite pas que l'application soit une application d'une seule page, il serait donc utile lorsque l'état doit circuler entre différentes demandes de page où la valeur CSRF ne peut normalement pas persister dans le navigateur).
Considérez les scénarios et processus suivants dans une application typique pour certains avantages et inconvénients de chaque approche que vous décrivez. Ceux-ci sont basés sur modèle de jeton de synchroniseur .
Demande d'approche du corps
Avantages:
Désavantages:
En-tête HTTP personnalisé (en aval)
Avantages:
Désavantages:
En-tête HTTP personnalisé (en amont)
Avantages:
Désavantages:
En-tête HTTP personnalisé (en amont et en aval)
Avantages:
Désavantages:
Set-Cookie
Avantages:
Désavantages:
L'approche des cookies est donc assez dynamique, offrant un moyen facile de récupérer la valeur du cookie (toute requête HTTP) et de l'utiliser (JS peut ajouter la valeur à n'importe quel formulaire automatiquement et il peut être utilisé dans les requêtes AJAX soit comme en-tête, soit comme un forme). Une fois le jeton CSRF reçu pour la session, il n'est pas nécessaire de le régénérer car un attaquant utilisant un exploit CSRF n'a pas de méthode pour récupérer ce jeton. Si un utilisateur malveillant essaie de lire le jeton CSRF de l'utilisateur dans l'une des méthodes ci-dessus, cela sera empêché par la même politique d'origine . Si un utilisateur malveillant essaie de récupérer le côté serveur de jeton CSRF (par exemple via
curl
), ce jeton ne sera pas associé au même compte d'utilisateur car le cookie de session d'authentification de la victime sera absent de la demande (ce serait l'attaquant - il ne sera donc pas associé côté serveur à la session de la victime).En plus du modèle de jeton de synchronisation, il existe également le cookie de double soumissionMéthode de prévention CSRF, qui utilise bien sûr des cookies pour stocker un type de jeton CSRF. Ceci est plus facile à implémenter car il ne nécessite aucun état côté serveur pour le jeton CSRF. Le jeton CSRF pourrait en fait être le cookie d'authentification standard lors de l'utilisation de cette méthode, et cette valeur est soumise via les cookies comme d'habitude avec la demande, mais la valeur est également répétée dans un champ ou un en-tête masqué, dont un attaquant ne peut pas se répliquer comme ils ne peuvent pas lire la valeur en premier lieu. Il serait toutefois recommandé de choisir un autre cookie, autre que le cookie d'authentification, afin que le cookie d'authentification puisse être sécurisé en étant marqué HttpOnly. C'est donc une autre raison courante pour laquelle vous trouverez la prévention CSRF en utilisant une méthode basée sur les cookies.
la source
L'utilisation d'un cookie pour fournir le jeton CSRF au client ne permet pas une attaque réussie car l'attaquant ne peut pas lire la valeur du cookie et ne peut donc pas le placer là où la validation CSRF côté serveur l'exige.
L'attaquant pourra provoquer une requête auprès du serveur avec à la fois le cookie de jeton d'authentification et le cookie CSRF dans les en-têtes de requête. Mais le serveur ne recherche pas le jeton CSRF en tant que cookie dans les en-têtes de demande, il recherche la charge utile de la demande. Et même si l'attaquant sait où placer le jeton CSRF dans la charge utile, il devrait lire sa valeur pour le mettre là. Mais la politique d'origine croisée du navigateur empêche la lecture de toute valeur de cookie du site Web cible.
La même logique ne s'applique pas au cookie de jeton d'authentification, car le serveur l'attend dans les en-têtes de demande et l'attaquant n'a rien à faire de spécial pour le mettre là.
la source
src='bank.com/transfer?to=hacker&amount=1000
lequel le navigateur demandera, avec les cookies associés pour ce site (bank.com
)?Ma meilleure supposition quant à la réponse: considérez ces 3 options pour savoir comment obtenir le jeton CSRF du serveur vers le navigateur.
Je pense que le premier, le corps de la demande (bien que démontré par le tutoriel Express que j'ai lié dans la question ), n'est pas aussi portable dans une grande variété de situations; tout le monde ne génère pas chaque réponse HTTP de manière dynamique; où vous finissez par avoir besoin de mettre le jeton dans la réponse générée peut varier considérablement (dans une entrée de formulaire cachée; dans un fragment de code JS ou une variable accessible par un autre code JS; peut-être même dans une URL bien que cela semble généralement un mauvais endroit pour mettre des jetons CSRF). Ainsi, bien qu'il soit réalisable avec une certaine personnalisation, le n ° 1 est un endroit difficile à faire pour une approche unique.
Le second, en-tête personnalisé, est attrayant mais ne fonctionne pas réellement, car bien que JS puisse obtenir les en-têtes d'un XHR qu'il a invoqué, il ne peut pas obtenir les en-têtes de la page à partir de laquelle il a été chargé .
Cela laisse le troisième, un cookie porté par un en-tête Set-Cookie, comme une approche facile à utiliser dans toutes les situations (le serveur de n'importe qui pourra définir des en-têtes de cookie par demande, et peu importe le type de les données se trouvent dans le corps de la demande). Malgré ses inconvénients, il s'agissait de la méthode la plus simple à mettre en œuvre largement pour les frameworks.
la source
Outre le cookie de session (qui est un peu standard), je ne veux pas utiliser de cookies supplémentaires.
J'ai trouvé une solution qui fonctionne pour moi lors de la création d'une application Web à page unique (SPA), avec de nombreuses demandes AJAX. Remarque: J'utilise Java côté serveur et JQuery côté client, mais pas de choses magiques, donc je pense que ce principe peut être implémenté dans tous les langages de programmation populaires.
Ma solution sans cookies supplémentaires est simple:
Côté client
Stockez le jeton CSRF qui est retourné par le serveur après une connexion réussie dans une variable globale (si vous souhaitez utiliser le stockage Web au lieu d'une amende globale, bien sûr). Demandez à JQuery de fournir un en-tête X-CSRF-TOKEN dans chaque appel AJAX.
La page principale "index" contient cet extrait JavaScript:
Du côté serveur
Lors d'une connexion réussie, créez un jeton CSRF aléatoire (et suffisamment long), stockez-le dans la session côté serveur et renvoyez-le au client. Filtrez certaines demandes entrantes (sensibles) en comparant la valeur d'en-tête X-CSRF-TOKEN à la valeur stockée dans la session: celles-ci doivent correspondre.
Les appels AJAX sensibles (données de formulaire POST et données GET JSON), et le filtre côté serveur les interceptant, se trouvent sous un chemin / dataservice / *. Les demandes de connexion ne doivent pas atteindre le filtre, elles sont donc sur un autre chemin. Les demandes de ressources HTML, CSS, JS et images ne sont pas non plus sur le chemin / dataservice / *, donc pas filtrées. Ceux-ci ne contiennent rien de secret et ne peuvent pas faire de mal, donc c'est très bien.
la source