4.7.5 Tester les Cross Site Request Forgeries (OTG-SESS-005)

Sommaire
Les Cross Site Request Forgeries CSRF sont des attaques qui forcent les utilisateurs à exécuter des actions non désirées dans une application sur laquelle ils sont actuellement authentifiés. Avec un peu d'ingénierie sociale, par exemple en envoyant un lien par courriel ou messagerie instantanée, un attaquant peut forcer les utilisateurs d'une application web à exécuter les actions qu'il veut. Si un utilisateur normal est visé, une attaque CSRF réussie va compromettre ses données et opérations. Si un compte administrateur est visé, c'est l'ensemble de l'application web qui peut être compromise.

Les CSRF utilisent les éléments suivants :

1) Le mode de traitement, par le navigateur, des informations liées aux sessions, telles que les cookies et authentifications HTTP ; 2) La connaissance par l'attaquant d'URLs valides de l'application web ; 3) Le management de sessions applicatives reposant uniquement sur des informations connues du navigateur ; 4) La présence de balises HTML donnant un accès direct à des ressources HTTP(S) ; par exemple des balises image img.

Les points 1, 2 et 3 sont requis pour la présence de la vulnérabilité, alors que le point 4 facilite l'exploitation réelle, mais n'est pas indispensable.

Point 1) Les navigateurs envoient l'information utilisée pour identifier une session utilisateur. Supposons que site héberge une application web, et que l'utilisateur victime s'est authentifié sur site. En réponse, site envoie à victime un cookie qui identifie les requêtes de victime comme appartenant à sa session authentifiée. En gros, une fois que le navigateur a reçu le cookie créé par site, il joindra ce cookie à toutes les requêtes suivantes destinées à site.

Point 2) Si l'application n'utilise pas d'informations de session intégrées dans les URLs, cela signifie que les URLs de l'application, leurs paramètres, et valeurs légitimes peuvent être identifiées (par analyse de code, ou en accédant à l'application et en relevant les formulaires et URLs embarqués dans HTML/JavaScript).

Point 3) Les informations connues par le navigateur comprennent les cookies, les informations d'authentification HTTP (telles que l'Authentification Basique ; et pas les authentifications basées sur des formulaires), qui sont stockées par le navigateur et jointes à chaque requête ultérieure envoyée la partie d'une application nécessitant cette authentification. Les vulnérabilités présentées plus bas concernent les applications qui reposent entièrement sur ce genre d'informations pour identifier une session utilisateur.

Prenons un cas simple : des URLs accessibles en GET (bien que cela puisse s'appliquer aussi bien à des requêtes POST). Si l'utilisateur victime est déjà authentifié, son cookie sera automatiquement joint à une autre requête (cf. l'image suivante, où l'utilisateur accède à l'application www.example.com).



La requête GET peut être générée de différentes manières :


 * Par l'utilisateur, qui est en train d'utiliser l'application web ;
 * Par l'utilisateur qui saisit directement l'URL dans le navigateur ;
 * Par l'utilisateur, qui suit un lien (externe à l'application) pointant sur l'URL.

Ces requêtes sont indifférenciables par l'application. La troisième en particulier peut être très dangereuse. Il y a de nombreuses techniques (et vulnérabilités) qui peuvent masquer les propriétés réelles d'un lien. Le lien peut être inséré dans un courriel, ou sur un site malicieux vers lequel l'utilisateur est envoyé, par exemple un lien intégré dans un contenu hébergé ailleurs (un autre site web, un courriel en HTML, etc.) et pointant vers une ressource de l'application. Si l'utilisateur clique sur le lien, comme il était déjà authentifié sur l'application web site, le navigateur envoie une requête GET vers l'application, accompagnée de l'information d'authentification (le cookie identifiant de session). Cela exécute donc une opération valide sur l'application, ce qui n'était probablement pas ce que l'utilisateur pensait faire. Pour imaginer les conséquences, il faut penser à un lien malicieux déclenchant un transfert sur une application bancaire.

En utilisant des balises tels que img, comme indiqué dans le point 4 plus haut, il n'est même pas nécessaire que l'utilisateur clique sur un lien particulier. Supposons que l'attaquant envoie un courriel à l'utilisateur, l'incitant à visiter une URL renvoyant sur une page contenant le code HTML (très simplifié) suivant :

...



...

Quand il va afficher cette page, le navigateur va essayer d'afficher l'image spécifiée, de taille nulle (donc invisible). Cela génère une requête automatique vers l'application web hébergée sur site. Le fait que l'URL de l'image ne pointe pas vers une véritable image n'a aucune importance, de toute façon, sa présence déclenche la requête indiquée dans le champs src. Cela fonctionne à condition que le téléchargement automatique des images ne soit pas désactivé dans le navigateur, mais c'est typiquement le cas puisque désactiver les images rendrait la plupart des applications web inutilisables.

Le problème, ici, est la conséquence des faits suivants :


 * Il y a des balises HTML dont la présence dans une page provoque des requêtes HTTP automatiques (img par exemple) ;
 * Le navigateur n'a aucun moyen de détecter que la ressource référencée par img n'est en réalité pas une image et est illégitime ;
 * le chargement d'images est effectif quelque soit la localisation de la prétendue image, c'est-à-dire que le formulaire et l'image elle-même n'ont pas besoin d'être localisés sur le même serveur, ni même dans le même domaine. Bien que ce soit une fonctionnalité pratique, cela rend difficile de compartimenter les applications.

Un tel type d'attaque est rendu possible par le fait qu'un contenu HTML extérieur puisse référencer des composants de l'application, et que le navigateur construise automatiquement des requêtes valides vers l'application. Comme aucun standard n'est défini actuellement, il n'y a aucun moyen d'interdire ce comportement sauf à rendre impossible à l'attaquant de référencer des URLs valides vers l'application. Cela signifie que les URLs doivent contenir des informations en rapport avec la session utilisateur, qui ne sont pas supposées être connues de l'attaquant, et ainsi rendre impossible l'identification de telles URLs.

Le problème peut être encore plus grave, puisque l'intégration d'environnement courriel/navigateur affichant simplement un message électronique contenant des images pourrait appeler l'application web avec le cookie associé au navigateur.

On peut envore mieux camoufler l'attaque, en référençant des URLs d'images d'apparence valides :



Ici [attacker] est un site contrôlé par l'attaquant, et en utilisant un mécanisme de redirection de http://[attacker]/picture.gif vers http://[thirdparty]/action.

Les cookies ne sont pas le seul exemple impliqué dans ce type de vulnérabilités. Les applications web dont les informations de session sont gérées uniquement par le navigateur sont aussi vulnérables. Cela inclut les applications reposant uniquement sur le mécanisme d'authentification HTTP, puisque l'information d'authentification est connue du navigateur et est envoyée automatiquement avec chaque requête. Cela ne concerne PAS l'authentification basée sur formulaire, qui n'intervient qu'une fois et génère une forme quelconque d'information de session (si une telle information est exprimée uniquement à l'aide d'un cookie, l'on peut bien sûr retomber dans les cas précédents).

Exemple de scenario.

Supposons que la victime soit connectée sur une application web de configuration de pare-feu. Pour se connecter, un utilisateur doit s'authentifier et les informations de session sont stockées dans un cookie.

Supposons que l'application web de configuration de pare-feu ait une fonction qui permet à un utilisateur authentifié de supprimer une règle désignée par son numéro d'ordre, ou de supprimer toutes les règles de la configuration si l'utilisateur entre '*' (fonctionnalité très dangereuse, mais elle rend l'exemple plus intéressant). La page de suppression est présentée ci-dessous. Supposons que le formulaire, pour la simplicité de l'exemple, utilise la méthode GET :

https://[target]/fwmgt/delete?rule=1

(pour supprimer le règle numéro 1)

https://[target]/fwmgt/delete?rule=*

(pour supprimer toutes les règles).

L'exemple est volontairement simpliste, mais démontre de manière simple les dangers des CSRF.



Ainsi, si on entre la valeur '*' et que l'on presse le bouton Supprimer, la requête suivante est envoyée.

https://www.company.example/fwmgt/delete?rule=*

avec pour effet de supprimer toutes les règles du pare-feu (et de se retrouver dans une situation potentiellement inopportune).



Ce n'est pas le seul scénario possible. L'utilisateur aurait pu obtenir les mêmes résultats en construisant l'URL manuellement :

https://[target]/fwmgt/delete?rule=*

Ou en cliquant sur un lien pointant, directement ou via une redirection, vers l'URL ci-dessus ; ou encore en accèdant à une page HTML contenant une balise img pointant sur la même URL.

Dans tous ces cas, si l'utilisateur est effectivement connecté sur l'application de configuration de pare-feu, la requête va réussir à modifier la configuration du pare-feu. On peut imaginer des attaques ciblant des applications sensibles et soumettant des enchères automatiques, procédant à des transferts d'argent, passant des commandes, changeant la configuration de composants logiciels critiques, etc.

Un aspect intéressant est que ces vulnérabilités peuvent être exploitées derrière un pare-feu ; c'est-à-dire qu'il suffit que le lien attaqué soit accessible par la victime (et non directement par l'attaquant). Cela peut être en particulier n'importe quel server web Intranet ; par exemple, le serveur de configuration de pare-feu mentionné plus haut, qui a peu de chances d'être exposé à Internet. Imaginez une attaque CSRF visant une application de surveillance d'une centrale nucléaire. C'est surement improbable, mais c'est une possibilité.

Des applications intrinsèquement vulnérables, pouvant être utilisées à la fois comme vecteur d'attaque et comme cible (comme des applications webmail), rendent la situation encore plus grave. Si une telle application est vulnérable, l'utilisateur est évidemment connecté lorsqu'il lit un message contenant une attaque CSRF, qui peut viser l'application webmail et la forcer à faire des actions comme supprimer des messages, envoyer des messages de la part de l'utilisateur, etc.

Test en boite noire
En boite noire, le testeur doit connaître les URLs de l'espace restreint (authentifié). S'il possède des accès valides, il peut assumer les deux rôles - attaquant et victime. Dans ce cas, le testeur découvre les URLs en naviguant simplement sur l'application.

Au contraire, si le testeur n'a pas d'accès valides, il doit organiser une attaque réelle, et inciter un utilisateur légitime, authentifié, à ouvrir un lien approprié. Cela peut nécessiter un certain niveau d'ingénierie sociale.

Dans tous les cas, un test peut être conçu comme suit :


 * soit u l'URL à tester ; par exemple u = http://www.example.com/action ;
 * construire une page contenant la requête HTTP reférençant l'URL u (précisant tous les paramètres nécessaires ; c'est trivial dans le cas d'une requête HTTP GET, alors qu'une requête POST nécessitera un peu de JavaScript) ;
 * s'assurer que l'utilisateur légitime est bien connecté à l'application ;
 * l'inciter à ouvrir le lien pointant sur l'URL à tester (par ingénierie sociale, si le testeur ne peut pas se faire passer lui-même pour l'utilisateur) ;
 * observer le résultat, c'est-à-dire vérifier si le serveur web a exécuté la requête.

Test en boite grise
Auditer l'application pour vérifier si son système de gestion de session est vulnérable. Si la gestion de session repose seulement sur des valeurs côté client (informations disponibles pour le navigateur), alors l'application est vulnérable. "Valeurs côté client" signifie cookies et informations d'authentification HTTP (Authentication Basique et autres formes d'authentification HTTP ; pas l'authentification basée sur formulaire, qui est une authentification au niveau applicatif). Pour qu'une application ne soit pas vulnérable, elle doit contenir des informations de session dans ses URL, sous une forme non-identifiable et imprévisible par l'utilisateur ([3] utilise le terme secret pour désigner ces informations).

Les ressources accessibles par requêtes HTTP GET sont facilement vulnérables, bien que les requêtes POST puissent être automatisées en JavaScript et soient aussi vulnérables ; ainsi, l'utilisation de POST n'est pas suffisante pour corriger les vulnérabilités CSRF.

Outils

 * WebScarab Spider http://www.owasp.org/index.php/Category:OWASP_WebScarab_Project
 * CSRF Tester http://www.owasp.org/index.php/Category:OWASP_CSRFTester_Project
 * Cross Site Requester http://yehg.net/lab/pr0js/pentest/cross_site_request_forgery.php (via img)
 * Cross Frame Loader http://yehg.net/lab/pr0js/pentest/cross_site_framing.php (via iframe)
 * Pinata-csrf-tool http://code.google.com/p/pinata-csrf-tool/

Références
Whitepapers
 * Peter W: "Cross-Site Request Forgeries" - http://www.tux.org/~peterw/csrf.txt
 * Thomas Schreiber: "Session Riding" - http://www.securenet.de/papers/Session_Riding.pdf
 * Oldest known post - http://www.zope.org/Members/jim/ZopeSecurity/ClientSideTrojan
 * Cross-site Request Forgery FAQ - http://www.cgisecurity.com/articles/csrf-faq.shtml
 * A Most-Neglected Fact About Cross Site Request Forgery (CSRF) -

Contre-mesures
Ci-dessous, des contre-mesures pour les utilisateurs et les développeurs.

Utilisateurs

Comme les attaques CSRF sont répandues, il est recommandé de suivre de bonnes pratiques pour minimiser les risques. Actions possibles :


 * Se déconnecter immédiatement après utilisation d'une application
 * Ne pas autoriser le navigateur à stocker des noms d'utilisateurs et des mots de passe, et ne pas autoriser les sites à "se souvenir" des identifiants de connexion.
 * Ne pas utiliser le même navigateur pour accèder des applications sensibles et pour naviguer librement sur Internet ; s'il est nécessaire de faire les deux sur la même machine, utiliser des navigateurs séparés.

L'intégration de clients de messagerie et de lecteurs de newsgroups avec les navigateurs pose des risques supplémentaires, puisque le simple affichage d'un message peut entraîner l'exécution d'une attaque.

Développeurs

Ajouter des informations de session dans les URLs. L'attaque est rendue possible parce que la session est uniquement identifiée par le cookie, qui est automatiquement envoyé par le navigateur. Générer d'autres informations spécifiques à la session au niveau de l'URL rend difficile pour l'attaquant la connaissance de la structure des URLs à attaquer.

Il y existe d'autre contre-mesures qui, bien qu'elles ne résolvent pas le problème, contribuent à le rendre plus difficile à exploiter :


 * Utiliser POST au lieu de GET. Bien que les requêtes POST puissent être simulées au moyen de JavaScript, elles rendent les attaques plus difficiles à concevoir.
 * Il en est de même ave les pages de confirmation intermédiaires (telles que : "Etes-vous sûr de vouloir faire cela ?"). Elles peuvent être contournées par l'attaquant, bien qu'elles rendent son travail un peu plus complexe. Il ne faut donc pas compter seulement sur ces mesures pour protéger l'application.
 * Les mécanismes de déconnexion automatique peuvent un peu limiter l'exposition à ces vulnérabilités, bien qu'au final cela dépende du contexte (un utilisateur qui travaille toute la journée sur une application web bancaire sera évidemment plus à risque qu'un utilisateur occasionnel de la même application).

Description des vulnérabilités CSRF
Voir l'article de l'OWASP sur les vulnérabilités CSRF.

Comment éviter les vulnérabilités CSRF
Voir l'article OWASP Development Guide sur Avoid CSRF.

Comment faire des revues de code pour les CSRF
Voir l'article OWASP Code Review Guide sur Review Code for CSRF.

Comment prévenir les vulnérabilités CSRF
Voir l'article OWASP CSRF Prevention Cheat Sheet sur les mesures de prévention.