La XSS, cette faille méconnue
3 août 2008 – 18:33En matière de sécurité des sites Web, la XSS est sans doute la faille incontournable, tant au niveau de sa popularité auprès des hackers débutants que du nombre impressionnant de sites vulnérables. Pour s’en rendre compte, il n’y a qu’à comparer le nombre de sites vulnérables aux XSS et ceux touchés par les injections SQL — qui, rien qu’eux, sont déjà nombreux. Cependant, contrairement aux injections SQL, les failles de type XSS ne sont pas exploitables au niveau du serveur lui-même, mais nécessitent la présence d’un client. C’est justement cette différence fondamentale qui, à mon avis, entraîne les gens à penser que la XSS est moins dangereuse que l’injection SQL. Beaucoup (trop) de développeurs pensent que la XSS ne permet que de voler les cookies des visiteurs, et imaginent que pour sécuriser leur site il suffit de faire des vérifications sur leurs IP. Comme nous allons le voir, ces deux idées reçues sont complètement fausses.
J’ai justement décidé de rédiger ce billet afin de sensibiliser les lecteurs aux véritables dangers qui se trouvent dans la face cachée de cet iceberg qu’est la faille XSS. Comme mon but n’est pas d’aider les script-kiddies à exploiter cette faille, je ne donnerai pas de code ni d’exploit tout fait. Je suppose que les lecteurs ayant quelques connaissances en JavaScript pourront tester eux-mêmes et vérifier la véracité de mes propos…
Les « vraies » possibilités de la XSS
Pour comprendre les enjeux qui se cachent derrière la faille XSS, revenons à la base : qu’est-ce qu’une XSS ? Les initiales XSS signifient Cross Site Scripting, le C ayant été remplacé par le X du fait que CSS signifie déjà Cascade Style Sheets. La faille XSS permet à un attaquant potentiel d’exécuter du code (un script) sur le navigateur du client. Elle apparaît quand un site Web affiche des variables provenant d’une entrée utilisateur sans les filtrer. Ainsi, le simple code PHP suivant est vulnérable :
<?php echo $_GET['var']; ?>
En effet, un attaquant visitant cette page contrôle directement (par le biais de l’URL) le contenu de la variable $_GET['var']
. Il peut alors insérer du code HTML ou JavaScript, et il s’exécutera comme s’il faisait partie du site Web.
Quel intérêt ? Tout simplement le fait de pouvoir manipuler un visiteur en lui donnant un lien piégé. En cliquant sur un lien exploitant la faille XSS, le navigateur du visiteur va afficher le code HTML du site et exécuter le code JavaScript. Cela permet alors de récupérer des informations propres au visiteur, puisque tout le code est exécuté comme s’il provenait du site original. En effet, il faut savoir que si un site X envoie par exemple un cookie à un visiteur, le site Y ne pourra pas le lire. Le fait que la XSS permette d’injecter un script malveillant directement dans le code envoyé par X va donc autoriser ce script à récupérer des informations telles que des cookies.
Mais la récupération de cookie est loin d’être la seule possibilité des XSS. A vrai dire, la XSS offre absolument toutes les possibilités qu’offre JavaScript, puisqu’elle permet l’exécution de code JS arbitraire sur le navigateur. Citons quelques exemples :
- Vol de cookies, détournement de session
- Accès aux mêmes privilèges que la victime
- Accès au contenu de pages protégées (du moment que la victime peut y accéder)
- Exécution de requêtes arbitraires en se faisant passer pour la victime
- Espionnage de la victime, récupération de toutes les actions effectuées telles que les pages visitées, les saisies dans les formulaires — qui contiennent au passage probablement des mots de passe
- Ouverture de fenêtres de téléchargement de logiciels (pouvant être des spywares, trojans, rootkits…) lorsque la victime surfe sur ce site auquel elle fait confiance — et par conséquent, baisse sa garde
Il faut bien comprendre que la faille XSS permet à l’attaquant d’avoir un accès direct au navigateur de la victime, et qu’il peut alors absolument tout faire sur le site en se faisant passer pour la victime. Si la victime est par exemple un utilisateur lambda d’un forum, l’attaquant pourra poster des messages sous son nom, modifier son profil, et même dans certains cas changer son mot de passe. Si la victime est l’administrateur du forum, je vous laisse imaginer les possibilités offertes…
Attention, il faut cependant bien voir que la XSS ne permet pas l’élévation de privilèges au delà de ceux de la victime, autrement dit un attaquant ne pourra pas faire plus que ne le peut sa victime. Par exemple, s’il piège un utilisateur lambda du forum, il ne pourra pas effectuer des tâches d’administration — à moins bien sûr qu’une autre faille soit présente sur le site.
Est-ce difficile à exploiter ?
Non ! Et c’est une raison de plus pour prendre au sérieux la menace réelle que constitue cette faille ! Concrètement, il suffit d’avoir quelques connaissances en JavaScript pour pouvoir exploiter une faille XSS sur un site de base non protégé. De plus, la popularité grandissante d’Ajax offre encore de nouvelles possibilités, puisque l’objet XMLHttpRequest permet d’effectuer des requêtes asynchrones sur le serveur. Cela permet d’effectuer des requêtes en se faisant passer pour la victime tout en restant invisible. Et même si Ajax ne permet pas d’effectuer de requêtes sur un autre serveur (les requêtes sur des serveurs autres que celui visité ne sont pas permises par le navigateur), il existe une technique permettant de passer outre et d’effectuer des requêtes cross-domain de façon détournée. Il devient alors possibles d’envoyer des requêtes sur un site distant, comme par exemple le site Web de l’attaquant.
Ainsi, en ayant un minimum de connaissances JavaScript, il est possible de concevoir un exploit permettant de dumper un site Web vers une base de données contrôlée par l’attaquant, tout en se faisant passer pour un visiteur et donc en ayant accès à toutes les pages qu’il peut voir. Ainsi, même si l’attaquant n’a aucune connaissance au préalable d’un site Web et des éventuelles zones à accès réservés, il peut étudier ces dumps en off-line de façon totalement invisible puisqu’il ne consulte jamais le serveur directement. Il pourra alors mettre au point un second exploit qui lui permettra par la suite d’effectuer véritablement l’attaque en effectuant des requêtes pour le compte de la victime.
Les techniques qui ne protègent pas un site contre les XSS
Les pratiques suivantes ne protègent en rien un site Web contre les XSS :
- Vérification les IP des visiteurs authentifiés — inutile puisque le code est exécuté par la victime !
- Protections par .htaccess — inutile puisque si la victime est authentifiée, la requête forgée pourra être exécutée
- Utilisation de HTTPS — ne change absolument rien, JavaScript et Ajax fonctionnent très bien en HTTPS…
Attention, je n’ai pas dit que ces mesures de protections étaient complètement inutiles ; juste que dans le cas de la XSS, elles le sont.
La seule solution pour en finir avec les XSS
On ne le répétera jamais assez, il faut filtrer toutes les entrées utilisateur, en particulier celles que l’on affiche sur le site. Cela est valable pour toutes les variables envoyées par GET, POST, récupérées via les cookies, et plus généralement tout ce qui transite dns les requêtes HTTP, comme les entêtes (dont le célèbre X-Forwarded-For) donc même certaines variables du tableau $_SERVER
de PHP. Pour être efficace, la fonction de filtrage doit :
- Remplacer les caractères spéciaux par leurs entités HTML correspondantes
- Supprimer toutes les balises HTML (dont <script>)
En fait, le deuxième point est inclus dans le premier, puisque les caractères < et > sont spéciaux et peuvent donc être remplacés.
En PHP, pour sécuriser efficacement les entrées utilisateurs contre les XSS, il faut utiliser la fonction htmlentities()
en n’oubliant pas de lui passer la constante ENT_QUOTES
en deuxième argument afin de considérer les guillemets simples et doubles comme des caractères spéciaux et de les remplacer elles aussi. Un exemple :
<?php echo htmlentities($_GET['var'], ENT_QUOTES); ?>
Ainsi ce code est sécurisé, contrairement au premier. L’utilisation de cette fonction permet de sécuriser des variables affichées aussi bien entre des balises que dans des valeurs d’attributs de balises, comme c’est le cas dans des champs de formulaires. En effet, comme les caractères <, >, ‘ et » sont filtrés, il est impossible de s’évader des champs et d’injecter du code JavaScript.
Il s’agit à ma connaissance de la seule protection valable pour sécuriser une variable contre les XSS dans toutes les conditions. L’utilisation d’autres fonction, comme par exemple striptags()
, ne suffit pas dans toutes les conditions puisques les guillemets ne sont pas filtrées, laissant la possibilité d’injecter des attributs supportant le JavaScript comme onload
, onmouseover
, etc.
La XSS, une faille finalement pas si inoffensive que ça…
Pour conclure, j’espère vous avoir convaincu que la faille XSS représente une réelle menace, et qu’il est très important de la prendre au sérieux. Si le filtrage des variables contre les injections SQL commence à rentrer dans les mœurs, on ne peut pas en dire autant pour les XSS. Et pourtant, cette dernière permet dans certains cas de rooter complétement un site…
3 réponses à “La XSS, cette faille méconnue”
Bonjour .
Le post date un peu .
Mais je bosse sur ce sujet de temps en temps en tant que développeur .
Il ne faut pas oublier que l’attaquant peut urlencoder rawurlencoder ses attaques via les urls .
Bruno
Par bruno le 23 février 2009
Bon billet. Tu donnes une bonne explication du potentiel des attaques via XSS qui peut aussi conduire à une attaque crsf et réaliser un keyloger par exemple !
Par Stéphane le 24 décembre 2009