🧬 Cross-Site Scripting XSS — Guide HTML IDEO-Lab
Guide interactif, didactique et opérationnel : modèle mental, familles XSS, contextes d’encodage, exemples sûrs, CSP, Trusted Types, frameworks, tests, incident response et checklist finale.
🧠 Vue d’ensemble XSS
Comprendre l’injection de script côté navigateur
FondamentauxNavigateurRisque métier🧩 Modèle mental du navigateur
Pourquoi le contexte change tout
HTML parserDOMContextes🧬 Familles de XSS
Reflected, Stored, DOM-based, mutation et blind XSS
TypologieStoredDOM🎯 Règle des contextes
HTML, attribut, JavaScript, CSS et URL
EncodageContexteOWASP💾 XSS stocké
Le risque persistant dans les contenus, profils et back-offices
StoredBase de donnéesBack-office🪞 XSS réfléchi
Paramètres, recherche et messages immédiats
ReflectedQuery stringErreur🌐 DOM XSS
Sources, sinks et frameworks front-end
DOMFront-endJavaScript🔐 Encodage de sortie
La défense numéro un contre le XSS classique
Output encodingEscapingTemplates🧼 Sanitization HTML
Quand le HTML riche est vraiment nécessaire
DOMPurifyAllowlistWYSIWYG🛡️ CSP et Trusted Types
Réduire l’impact et verrouiller les sinks modernes
CSPNonceTrusted Types🍪 Sessions, cookies et impact
Limiter les dégâts quand une faille existe
HttpOnlySameSiteSession🏗️ Frameworks modernes
Django, React, Vue, Angular et composants tiers
DjangoReactTemplates🔎 Détection et tests
SAST, DAST, revue manuelle et tests navigateur
SASTDASTQA🚧 WAF / WAAP et limites
Filtrer ne remplace pas corriger
WAFWAAPDefense in depth🚨 Réponse à incident XSS
Contenir, enquêter, corriger et communiquer
IncidentSOCForensics🎮 Mini-lab pédagogique
Apprendre sans mettre en danger
LudiqueLabDidactique🏰 Architecture anti-XSS
Contrôles empilés du code au navigateur
ArchitectureSecure by designSDLC📌 Cheat-sheet finale
Décisions rapides, checklist et références
SynthèseChecklistRéférencesVue d’ensemble XSS
Le Cross-Site Scripting correspond à une injection de contenu interprété par le navigateur comme du code actif. Le cœur du problème n’est pas seulement l’entrée utilisateur, mais le moment où une donnée non fiable franchit une frontière de contexte : HTML, attribut, URL, JavaScript, CSS ou DOM. La défense repose sur un principe simple et exigeant : aucune donnée non fiable ne doit atteindre un contexte exécutable sans encodage, validation, sanitation ou isolation adaptés.
Mécanique
Un navigateur n’exécute pas une page comme un texte linéaire. Il parse successivement du HTML, des attributs, des URL, du CSS, du JavaScript et des événements DOM. Une même chaîne peut être inoffensive dans un texte HTML, dangereuse dans un attribut, catastrophique dans une chaîne JavaScript et ambiguë dans une URL. La sécurité XSS est donc une sécurité de contexte, pas une simple recherche de caractères interdits.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Mini-scène pédagogique
Anti-pattern
Recherche affichée directement : <p>Résultat pour : {{ q|safe }}</p>
La donnée q peut devenir une partie de la page plutôt qu’un simple texte.Correction attendue
Recherche affichée comme texte : <p>Résultat pour : {{ q }}</p>
Le moteur de template encode la donnée dans le contexte HTML attendu.Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Modèle de défense principal : auto-escaping par défaut, encodage contextuel, refus des HTML arbitraires, sanitation contrôlée lorsque du HTML riche est réellement nécessaire, CSP stricte, cookies HttpOnly/Secure/SameSite et revue des points d’injection DOM.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| Risque | La page exécute du code non prévu dans la session de la victime. |
| Impact | Vol de session, actions frauduleuses, défiguration, pivot interne, fraude métier. |
| Contrôle clé | Traiter toute donnée externe comme non fiable jusqu’à sa sortie contrôlée. |
| Erreur classique | Valider en entrée puis oublier l’encodage de sortie. |
Checklist
- Cartographier les zones où les données utilisateur sont réaffichées.
- Identifier les contextes de sortie : HTML, attribut, JS, URL, CSS, DOM.
- Interdire les contournements de template du type safe/raw sans justification.
- Prévoir un test XSS dans chaque revue de fonctionnalité exposée.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
Modèle mental du navigateur
Le navigateur est une machine à interpréter plusieurs langages imbriqués. Il construit le DOM à partir du HTML, applique des attributs et styles, charge des ressources, puis exécute des scripts qui peuvent relire et modifier la page. Le XSS apparaît lorsqu’une donnée prévue comme texte devient balise, attribut, URL, gestionnaire d’événement, fragment JavaScript ou entrée d’un sink DOM dangereux.
Mécanique
La même valeur traverse souvent plusieurs couches : requête HTTP, serveur, template, JSON, JavaScript client, DOM. Chaque changement de couche peut créer un nouveau contexte. Une donnée encodée correctement pour du HTML peut devenir dangereuse si elle est ensuite réutilisée dans un script ou injectée via innerHTML. Les failles modernes viennent souvent de ces réutilisations invisibles.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Chaîne de confiance simplifiée
Anti-pattern
const name = new URLSearchParams(location.search).get("name");
document.querySelector("#hello").innerHTML = name; // anti-pattern pédagogiqueCorrection attendue
const name = new URLSearchParams(location.search).get("name");
document.querySelector("#hello").textContent = name; // texte, pas HTMLRaison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Séparer strictement les intentions : textContent pour du texte, setAttribute seulement avec valeurs validées, URL construites par API, HTML riche uniquement après sanitation, interdiction de document.write, eval, Function, innerHTML non contrôlé et insertAdjacentHTML non filtré.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| Source | URL, fragment, postMessage, localStorage, API, WebSocket, cookie accessible JS. |
| Sink | innerHTML, outerHTML, document.write, insertAdjacentHTML, srcdoc, eval, setTimeout string. |
| Frontière | Moment où une donnée devient interprétable par le navigateur. |
| Bonne pratique | Choisir une API sûre plutôt que filtrer après coup. |
Checklist
- Lister les sources de données côté client.
- Lister les sinks DOM dangereux.
- Remplacer innerHTML par textContent lorsque du HTML n’est pas requis.
- Ajouter des tests unitaires sur les composants qui rendent du contenu externe.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
Familles de XSS
Les catégories historiques restent utiles : XSS réfléchi lorsque la donnée revient immédiatement dans la réponse, XSS stocké lorsqu’elle persiste en base ou dans un système intermédiaire, DOM XSS lorsque le client transforme une donnée non fiable en code. Des variantes existent : mutation XSS, blind XSS dans des back-offices, XSS via Markdown, SVG, PDF viewer, templates client ou widgets tiers.
Mécanique
Le reflected XSS touche souvent les paramètres de recherche, messages d’erreur ou redirections. Le stored XSS vise commentaires, profils, tickets, noms de fichiers, logs visibles, champs CMS. Le DOM XSS naît dans les scripts front-end : une source comme location.hash ou postMessage alimente un sink comme innerHTML. Le blind XSS se déclenche plus tard, dans une console admin ou un outil support.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Cartographie rapide
Anti-pattern
Champ commentaire enregistré puis rendu avec un filtre raw/safe dans le back-office.Correction attendue
Champ commentaire rendu comme texte, ou HTML autorisé passé dans un sanitizer avec allowlist stricte.Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
La priorité est plus élevée pour le XSS stocké et blind, car l’exploitation peut toucher des comptes internes privilégiés. Les flux support, CRM, admin, ticketing, logs et observabilité doivent être traités comme des surfaces de rendu à part entière.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| Reflected | Requête → réponse immédiate. Testable sur paramètres et messages. |
| Stored | Donnée persistée → affichage futur. Impact souvent plus fort. |
| DOM-based | Source client → sink client. Ne se voit pas toujours dans la réponse serveur. |
| Blind | Déclenchement différé dans un outil interne ou back-office. |
Checklist
- Classer chaque finding XSS par famille.
- Prioriser stored/blind/admin.
- Tester les zones d’administration, pas seulement le front public.
- Inclure les champs peu visibles : nom fichier, libellé, tag, user-agent, logs.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
Règle des contextes
La prévention XSS repose sur une règle centrale : l’encodage doit correspondre au contexte exact de sortie. Un encodage HTML ne protège pas nécessairement une chaîne JavaScript. Un encodage URL ne protège pas un attribut événementiel. Un attribut HTML sans guillemets est plus difficile à sécuriser. Le contexte détermine la défense, pas le nom du champ ni sa provenance.
Mécanique
Les parseurs changent de mode selon les caractères rencontrés. Dans le corps HTML, les caractères critiques sont notamment <, >, &, guillemets selon le contexte. Dans un attribut, les guillemets et espaces modifient la structure. Dans JavaScript, les quotes, backticks, antislashs, fins de ligne et séquences Unicode ont une autre signification. Dans CSS et URL, d’autres règles s’appliquent. Une solution générique unique est donc insuffisante.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Table de décision
Anti-pattern
<a href="{{ user_url }}">Profil</a> sans validation de schéma ni encodage adapté.Correction attendue
Valider le schéma http/https, normaliser l’URL, encoder l’attribut, refuser javascript:, data: et schémas inattendus.Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Appliquer la matrice OWASP : HTML encode pour le texte, attribute encode pour les attributs, JavaScript encode pour les chaînes JS, URL encode pour les paramètres, CSS encode si un contexte CSS est absolument nécessaire. Éviter les contextes dangereux quand une API sûre existe.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| HTML body | Échapper les caractères qui créent des balises ou entités. |
| Attribut HTML | Toujours mettre les valeurs entre guillemets et encoder l’attribut. |
| JavaScript string | Préférer JSON sérialisé et escape JS contextuel. |
| URL | Valider schéma/hôte puis encoder les paramètres. |
| CSS | Éviter les valeurs dynamiques ; utiliser allowlist stricte. |
Checklist
- Identifier le contexte de chaque interpolation.
- Supprimer les attributs événementiels dynamiques.
- Éviter les templates JS inline avec variables non sérialisées.
- Ajouter une revue dédiée aux href, src, srcdoc, style et data-* exploités par JS.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
XSS stocké
Le XSS stocké est particulièrement dangereux, car la charge est persistée puis servie à plusieurs utilisateurs, parfois à des administrateurs. Les zones classiques sont commentaires, biographies, noms de projet, champs CRM, tickets support, logs applicatifs, noms de fichiers, notifications, messages internes et contenu CMS.
Mécanique
La donnée peut être proprement validée à l’entrée, puis devenir dangereuse à la sortie si elle est rendue dans le mauvais contexte. Un nom de fichier affiché dans un tableau admin, un user-agent dans un viewer de logs ou le titre d’un ticket dans une notification HTML peuvent devenir des points d’exécution. Le XSS stocké se nourrit des interfaces secondaires que personne ne considère comme publiques.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Ticket support
Anti-pattern
Titre ticket enregistré : contenu utilisateur rendu en HTML dans une console support avec |safe.Correction attendue
Titre ticket rendu comme texte ; description riche sanitizée côté serveur ; aperçu admin soumis aux mêmes règles que le front.Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Contrôler les rendus back-office avec la même rigueur que les pages publiques. Séparer texte simple et HTML riche. Mettre en place une sanitation allowlist pour les éditeurs WYSIWYG, journaliser les nettoyages et conserver une version brute non affichée uniquement si nécessaire.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| Signal faible | Une donnée “interne” est affichée sans escaping. |
| Impact | Compromission d’un compte support/admin ou action en masse. |
| Test | Créer du contenu neutralisé et vérifier le rendu dans toutes les vues. |
| Mesure | Aucun rendu safe/raw sans justification de sécurité. |
Checklist
- Auditer admin, support, CRM, reporting, exports HTML.
- Traiter logs et user-agent comme entrées hostiles.
- Désactiver HTML riche si non nécessaire.
- Ajouter une validation sécurité aux composants de rendu communs.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
XSS réfléchi
Le XSS réfléchi survient lorsqu’une donnée fournie dans une requête HTTP est intégrée immédiatement dans la réponse de manière non sûre. Il concerne souvent les pages de recherche, filtres, messages d’erreur, paramètres de redirection, pages de statut, formulaires et bannières de confirmation.
Mécanique
L’exploitation dépend fréquemment d’un lien transmis à une victime. Le risque réel dépend du contexte d’exécution, des cookies, des droits de la victime, de la CSP et des protections de session. Même lorsqu’il n’y a pas de persistance, l’impact peut être élevé si la victime est authentifiée ou si la page contient des données sensibles.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Recherche
Anti-pattern
<p>Recherche : {{ request.GET.q|safe }}</p>Correction attendue
<p>Recherche : {{ request.GET.q }}</p> avec auto-escape et aucun HTML attendu.Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Ne jamais utiliser de filtre raw/safe pour un paramètre de requête. Définir un composant d’affichage des messages qui encode systématiquement. Tester les paramètres q, search, next, redirect, error, msg, tab, returnUrl et fragment exploité côté client.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| Surface | Paramètres GET/POST et messages instantanés. |
| Symptôme | La valeur saisie apparaît dans la page. |
| Contrôle | Encodage contextuel au rendu. |
| Renfort | CSP avec nonce et cookies HttpOnly/SameSite. |
Checklist
- Tester les paramètres visibles dans l’HTML.
- Vérifier les pages d’erreur personnalisées.
- Refuser les redirections ouvertes dangereuses.
- Contrôler les bannières flash/messages système.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
DOM XSS
Le DOM XSS se produit côté client lorsque du JavaScript lit une donnée non fiable puis l’insère dans un sink capable d’interpréter du HTML, du script ou une URL active. Les frameworks modernes réduisent certaines erreurs, mais les réintroduisent via HTML brut, composants tiers, templates client, Markdown, routeurs, postMessage ou manipulation directe du DOM.
Mécanique
Une page peut sembler sûre côté serveur : aucune charge dangereuse n’apparaît dans la réponse initiale. Pourtant, le code client peut lire location.hash, localStorage, postMessage ou une réponse API et construire ensuite du HTML. Les scans purement serveur ratent souvent cette classe ; il faut analyser le flux source → sink dans le JavaScript exécuté.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Source → sink
Anti-pattern
const html = location.hash.slice(1);
preview.innerHTML = html;Correction attendue
const text = location.hash.slice(1);
preview.textContent = text;Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Remplacer les sinks dangereux par des API textuelles. Pour le HTML riche, centraliser un sanitizer robuste, imposer Trusted Types quand possible, interdire les manipulations DOM brutes hors composants approuvés et surveiller les dépendances front-end.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| Sources | location, hash, search, postMessage, localStorage, API, WebSocket. |
| Sinks | innerHTML, outerHTML, insertAdjacentHTML, document.write, srcdoc. |
| Détection | Taint analysis, revue JS, tests dynamiques navigateur. |
| Contrôle | textContent, DOM APIs sûres, sanitizer, Trusted Types. |
Checklist
- Chercher innerHTML et insertAdjacentHTML dans le dépôt.
- Contrôler les handlers postMessage et origines autorisées.
- Encadrer les composants Markdown/WYSIWYG.
- Activer un mode CSP report-only pour repérer les scripts inline.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
Encodage de sortie
L’encodage de sortie transforme une donnée non fiable en représentation textuelle sûre dans un contexte donné. Il ne supprime pas la donnée ; il empêche le navigateur de l’interpréter comme structure ou code. C’est la défense fondamentale pour les contenus simples : noms, titres, commentaires texte, résultats de recherche, labels, messages et valeurs affichées.
Mécanique
L’encodage doit se produire le plus près possible de la sortie, car le contexte final est connu à cet endroit. Encoder trop tôt peut provoquer des doubles encodages ou donner une fausse impression de sécurité. La validation d’entrée reste utile pour la qualité métier, mais ne remplace pas l’encodage de sortie.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Django template
Anti-pattern
{{ comment.body|safe }} {# dangereux si comment.body vient d’un utilisateur #}Correction attendue
{{ comment.body }} {# auto-escape HTML par défaut #}Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Utiliser les mécanismes natifs du framework. Interdire les sorties raw/safe par défaut. Prévoir des helpers spécifiques par contexte. Les données destinées à JavaScript doivent être sérialisées en JSON sûr, pas concaténées dans un script inline.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| HTML texte | Auto-escape du moteur de template. |
| Attribut | Guillemets + escape attribut. |
| JS | Sérialisation JSON ou escapejs contextuel. |
| URL param | Construction par API URLSearchParams. |
| HTML riche | Sanitizer, pas simple escaping. |
Checklist
- Rechercher safe, raw, mark_safe, dangerouslySetInnerHTML.
- Documenter chaque exception.
- Créer un helper unique pour JSON dans script.
- Tester les caractères < > & " '.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
Sanitization HTML
La sanitation consiste à accepter du HTML contrôlé tout en retirant les balises, attributs et protocoles dangereux. Elle est nécessaire pour commentaires riches, éditeurs WYSIWYG, contenus CMS, documentation, Markdown converti en HTML ou imports externes. Elle doit être basée sur une allowlist explicite, pas sur une blacklist fragile.
Mécanique
Un sanitizer robuste comprend les subtilités de parsing HTML/SVG/MathML, les attributs événementiels, URL dangereuses, namespaces, mutations DOM et cas limites navigateur. Une regex maison est insuffisante. La sanitation doit être appliquée avant l’insertion dans le DOM et configurée selon le besoin exact : tags autorisés, attributs autorisés, protocoles autorisés, liens rel=noopener, images éventuellement proxyfiées.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
HTML riche contrôlé
Anti-pattern
preview.innerHTML = markdownToHtml(userMarkdown); // sans sanitationCorrection attendue
const dirty = markdownToHtml(userMarkdown);
const clean = DOMPurify.sanitize(dirty, { USE_PROFILES: { html: true } });
preview.innerHTML = clean;Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Centraliser la sanitation, figer une configuration, tester les régressions, surveiller les mises à jour du sanitizer, éviter les profils trop permissifs et ne jamais réactiver les attributs événementiels. Le HTML riche doit rester une exception métier.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| Allowlist | Balises et attributs explicitement autorisés. |
| Protocoles | http/https/mailto selon besoin ; refuser javascript/data sauf cas strict. |
| Markdown | Convertir puis sanitiser le HTML produit. |
| Stockage | Stocker brut + rendu nettoyé selon politique, ou nettoyer à la sortie. |
Checklist
- Justifier le besoin de HTML riche.
- Utiliser un sanitizer maintenu.
- Tester SVG, liens, images, tableaux et attributs data.
- Interdire la configuration locale dispersée.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
CSP et Trusted Types
Content Security Policy n’est pas une excuse pour oublier l’encodage, mais un filet de sécurité très précieux. Une CSP stricte réduit l’exécution de scripts non autorisés, limite les sources de ressources, bloque certains comportements dangereux et fournit des rapports. Trusted Types ajoute un verrou côté navigateur sur les sinks DOM sensibles.
Mécanique
Une CSP efficace évite 'unsafe-inline', utilise des nonces ou hashes pour les scripts autorisés, définit object-src 'none', base-uri 'self', frame-ancestors, connect-src et img-src selon le besoin. Trusted Types force certains sinks à recevoir des objets TrustedHTML/TrustedScript créés par des politiques explicites, ce qui rend les erreurs innerHTML beaucoup plus visibles.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Politique de départ
Anti-pattern
Content-Security-Policy: script-src * 'unsafe-inline' 'unsafe-eval'Correction attendue
Content-Security-Policy: default-src 'self'; script-src 'self' 'nonce-{RANDOM}'; object-src 'none'; base-uri 'self'; require-trusted-types-for 'script'; trusted-types app-sanitizer;Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Déployer en report-only, corriger les violations, puis passer en enforcement. Les nonces doivent être uniques par réponse. Les bibliothèques tierces doivent être inventoriées. La CSP doit être testée automatiquement afin d’éviter les assouplissements accidentels.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| script-src | Sources de scripts et nonces/hashes. |
| object-src | none dans la majorité des applications modernes. |
| base-uri | self pour éviter les détournements de résolution. |
| report-uri/report-to | Collecte des violations CSP. |
| Trusted Types | Contrôle type-level des sinks DOM. |
Checklist
- Commencer par report-only.
- Supprimer les scripts inline non nécessaires.
- Mettre en place nonces côté serveur.
- Collecter et analyser les rapports CSP.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
Sessions, cookies et impact
Une faille XSS s’exécute dans le navigateur de la victime. Les cookies, tokens, données du DOM, actions applicatives et API accessibles par la session sont donc exposés. Les flags HttpOnly, Secure et SameSite ne corrigent pas le XSS, mais ils réduisent certains impacts, notamment le vol direct de cookie par JavaScript.
Mécanique
HttpOnly empêche JavaScript de lire un cookie, mais n’empêche pas une action authentifiée depuis la page compromise. SameSite réduit certaines attaques intersites, Secure impose HTTPS, et une rotation de session limite la durée d’exploitation. Les tokens stockés dans localStorage restent accessibles au JavaScript injecté et constituent donc un risque important.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Cookie de session durci
Anti-pattern
Set-Cookie: sessionid=abc123Correction attendue
Set-Cookie: sessionid=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=3600Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Limiter les données sensibles accessibles dans le DOM, éviter les tokens persistants dans localStorage, préférer cookies HttpOnly pour sessions web, isoler les privilèges admin, ajouter confirmations serveur pour actions sensibles et surveiller les comportements anormaux post-XSS.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| HttpOnly | Réduit le vol direct du cookie par JS. |
| Secure | Transmission uniquement via HTTPS. |
| SameSite | Réduit certains envois cross-site. |
| localStorage | Accessible au JavaScript injecté : prudence maximale. |
| Actions sensibles | Revalidation, MFA step-up, anti-CSRF et logs. |
Checklist
- Vérifier flags cookies en production.
- Éviter tokens sensibles dans localStorage.
- Segmenter les sessions admin.
- Ajouter step-up pour actions critiques.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
Frameworks modernes
Les frameworks modernes protègent contre beaucoup de XSS classiques grâce à l’échappement automatique et aux abstractions DOM. Mais ces protections tombent dès que le code contourne le rendu normal : safe/raw, mark_safe, dangerouslySetInnerHTML, v-html, bypassSecurityTrust*, templates inline, HTML tiers ou manipulation DOM directe.
Mécanique
La règle est simple : rester dans le chemin sûr du framework. Dans Django, l’autoescape protège le rendu HTML standard ; les filtres safe/mark_safe doivent être exceptionnels. Dans React, l’interpolation texte est échappée ; dangerouslySetInnerHTML doit être réservé au HTML sanitizé. Dans Angular, les bypass de sanitizer sont des exceptions de sécurité. Les composants tiers doivent être considérés comme code exécutable importé.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Chemins sûrs et dangereux
Anti-pattern
React : <div dangerouslySetInnerHTML={{ __html: userHtml }} />
Django : {{ user_html|safe }}Correction attendue
React : <div>{userText}</div>
Django : {{ user_text }}
HTML riche : sanitizer central + revue sécurité.Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Créer une politique d’usage par framework. Bloquer les exceptions dans les linters lorsque possible. Encapsuler les rendus HTML riches dans un composant unique, testé, documenté et surveillé. Refuser les composants tiers qui injectent du HTML sans contrôle.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| Django | Autoescape par défaut ; prudence safe/mark_safe. |
| React | Interpolation sûre ; danger sur dangerouslySetInnerHTML. |
| Vue | Moustaches sûres ; danger sur v-html. |
| Angular | Sanitization intégrée ; danger sur bypassSecurityTrust*. |
| jQuery legacy | html() dangereux avec données non fiables. |
Checklist
- Scanner les contournements framework.
- Créer une liste d’exceptions approuvées.
- Auditer composants tiers et éditeurs riches.
- Former les équipes front/back sur les contextes.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
Détection et tests
La détection XSS combine plusieurs approches. Le SAST repère les flux source → sink dans le code. Le DAST observe le comportement de l’application. La revue manuelle identifie les contextes subtils. Les tests navigateur détectent le DOM XSS, les comportements de composants et les régressions CSP. Aucun outil ne couvre tout seul l’ensemble des cas.
Mécanique
Un bon plan de test commence par l’inventaire des entrées : formulaires, URL, API, import fichiers, WebSocket, postMessage, Markdown, WYSIWYG, logs, champs admin. Chaque entrée est suivie jusqu’aux sorties. Les tests doivent utiliser des chaînes canaris neutralisées qui révèlent les changements de contexte sans déclencher de charge agressive.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Canari neutralisé
Anti-pattern
Test limité à “le champ est validé en entrée”.Correction attendue
Injecter une chaîne canari encodée dans chaque champ, puis vérifier tous les rendus : front, admin, email HTML, export, logs, notifications.Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Intégrer les tests XSS dans CI/CD : règles Semgrep/CodeQL, tests Playwright/Cypress, scan DAST en préproduction, revue des CSP reports et couverture des templates. Les findings doivent indiquer contexte, source, sink, impact et correction recommandée.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| SAST | Trouve patterns dangereux dans le code. |
| DAST | Observe réponses et comportements applicatifs. |
| IA/assistant code | Aide à repérer anti-patterns, mais nécessite validation. |
| Manual review | Indispensable pour contextes complexes. |
| Browser tests | Nécessaires pour DOM XSS et CSP. |
Checklist
- Inclure XSS dans la définition de terminé.
- Tester front public et back-office.
- Automatiser recherche safe/raw/innerHTML.
- Documenter chaque correction avec contexte exact.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
WAF / WAAP et limites
Un WAF ou WAAP peut réduire l’exposition, bloquer des patterns connus, ralentir l’exploitation et fournir de la télémétrie. Il ne remplace pas l’encodage contextuel, la sanitation ni la correction de code. Le XSS dépend du contexte applicatif ; un filtre réseau ne sait pas toujours comment le navigateur interprétera la donnée finale.
Mécanique
Les filtres génériques peuvent produire des faux positifs, rater des encodages alternatifs, ignorer le DOM XSS client ou bloquer des usages légitimes. Ils sont utiles comme couche de protection, notamment lors d’une crise ou en attente de patch, mais la correction durable doit se situer dans le rendu applicatif et les composants front-end.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Positionnement correct
Anti-pattern
Finding XSS fermé parce que “le WAF bloque la chaîne de test”.Correction attendue
WAF utilisé en mitigation temporaire ; ticket de correction maintenu jusqu’à encodage/sanitation côté application.Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Définir le WAF comme contrôle compensatoire. Surveiller les faux positifs, conserver les logs, corréler avec les endpoints vulnérables et retirer les règles temporaires après correction. Ne pas exposer d’exception globale qui affaiblit toute l’application.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| Forces | Blocage rapide, visibilité, règles virtuelles temporaires. |
| Limites | Contexte incomplet, DOM XSS, contournements, faux positifs. |
| Bon usage | Mitigation en profondeur et protection transitoire. |
| Mauvais usage | Remplacer la correction applicative par une règle réseau. |
Checklist
- Marquer les règles WAF temporaires.
- Relier chaque règle à un ticket de correction.
- Analyser les endpoints les plus touchés.
- Ne jamais considérer le WAF comme unique défense XSS.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
Réponse à incident XSS
Lorsqu’un XSS est exploité, l’incident ne se limite pas au patch. Il faut identifier les victimes potentielles, les actions effectuées dans leurs sessions, les données consultées, les contenus stockés, la persistance éventuelle et les comptes à privilèges exposés. Le périmètre dépend du type de XSS, des logs disponibles et des protections de session.
Mécanique
La chronologie doit relier point d’entrée, payload neutralisé ou contenu suspect, première apparition, pages touchées, comptes victimes, appels API anormaux, changements de configuration, transferts de données et éventuelles escalades. En cas de stored XSS, la suppression ou neutralisation du contenu stocké est prioritaire avant même la correction complète.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Runbook court
Anti-pattern
Corriger le template puis fermer l’incident sans vérifier les sessions et actions passées.Correction attendue
Neutraliser le contenu, bloquer exploitation, invalider sessions exposées, analyser logs, corriger, déployer CSP/monitoring, rédiger post-mortem.Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Préparer des playbooks : purge contenu, invalidation sessions, rotation tokens, désactivation temporaire de rendu HTML riche, règle WAF transitoire, collecte CSP reports, revue des comptes admin et communication conforme au niveau de risque.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| Containment | Supprimer contenu stocké, règle temporaire, désactivation feature. |
| Eradication | Correction contextuelle, tests de non-régression. |
| Recovery | Redéploiement, monitoring, rotation sessions/tokens. |
| Lessons learned | Composant commun, linter, formation, tests CI. |
Checklist
- Conserver les preuves avant purge si possible.
- Invalider les sessions à risque.
- Vérifier actions sensibles réalisées pendant la fenêtre.
- Ajouter tests et règles de détection après correction.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
Mini-lab pédagogique
Un apprentissage efficace du XSS repose sur des exercices courts : identifier le contexte, choisir la défense, corriger le code, vérifier que le rendu reste fonctionnel. Un mini-lab interne peut proposer des chaînes canaris inoffensives, des templates volontairement vulnérables et des corrections guidées, sans fournir de charges orientées vol de données ou contournement offensif.
Mécanique
Le jeu pédagogique peut suivre un format en quatre cartes : source, contexte, sink, correction. L’apprenant reçoit un extrait de code, identifie le contexte de sortie, choisit la bonne API ou le bon encodage, puis vérifie le résultat. Les scores ne récompensent pas l’attaque, mais la correction : suppression du sink dangereux, choix du contexte, test de non-régression et explication claire.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Carte de jeu
Anti-pattern
Niveau 1 : “Le message utilisateur est rendu avec innerHTML. Trouver le problème.”Correction attendue
Solution : remplacer par textContent, ajouter test, expliquer pourquoi la donnée devait rester du texte.Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Les labs doivent être isolés, non connectés à des données réelles, sans authentification production et avec des payloads neutralisés. L’objectif est la maîtrise des défenses et du raisonnement par contexte.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| Niveau 1 | HTML body : escaping simple. |
| Niveau 2 | Attribut href : validation schéma + encodage. |
| Niveau 3 | DOM XSS : source → sink. |
| Niveau 4 | HTML riche : sanitizer + CSP. |
| Niveau 5 | Incident : containment + correction + post-mortem. |
Checklist
- Créer des exercices par contexte.
- Utiliser des chaînes canaris neutralisées.
- Noter la correction, pas la charge.
- Intégrer les résultats à la formation développeur.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
Architecture anti-XSS
Une architecture anti-XSS robuste combine des contrôles au niveau code, template, framework, composants front-end, headers HTTP, sessions, dépendances, tests et supervision. La meilleure défense est un chemin sûr par défaut : les développeurs n’ont pas à se souvenir de chaque règle si les composants communs rendent les mauvais choix difficiles.
Mécanique
Le modèle cible impose : autoescape actif, composants de rendu communs, helper unique pour HTML riche, sanitizer central, CSP stricte, Trusted Types pour les applications compatibles, cookies durcis, linters anti-sinks, tests CI, revue des exceptions, inventaire des composants tiers et observabilité CSP. Les exceptions existent, mais elles sont documentées, validées et révisées.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Pipeline sécurisé
Anti-pattern
Chaque équipe choisit ses propres helpers, sanitizers et exceptions safe/raw.Correction attendue
Bibliothèque interne de rendu : Text, SafeLink, RichHtmlSanitized, JsonScript, MarkdownSafe, tous testés et documentés.Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Mettre la sécurité dans les abstractions : composants UI, middlewares, headers, templates de base, conventions de code, CI/CD et revues. Les règles doivent être visibles dans le dépôt et vérifiées automatiquement.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| Code | APIs sûres, pas de sink brut. |
| Template | Autoescape, helpers contextuels. |
| Navigateur | CSP, Trusted Types, headers de sécurité. |
| Session | Cookies durcis, step-up actions sensibles. |
| SDLC | SAST/DAST/tests/revue exceptions. |
Checklist
- Créer des composants de rendu communs.
- Bloquer les patterns dangereux en CI.
- Standardiser CSP et cookies.
- Revoir régulièrement les exceptions.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
Cheat-sheet finale
La prévention XSS peut se résumer en une phrase : une donnée non fiable doit rester du texte, sauf décision explicite, contrôlée et testée de l’interpréter autrement. Les mécanismes de sécurité doivent être contextuels, centralisés, testés et observables.
Mécanique
Le réflexe opérationnel suit cinq questions : quelle est la source ? quel est le contexte de sortie ? quel sink reçoit la donnée ? quelle défense est appliquée ? quel test prouve que le navigateur ne change pas d’interprétation ? Si une seule réponse manque, la zone mérite une revue.
Chaîne source → sink
Source non fiable ↓ Transformation / stockage ↓ Contexte de sortie ↓ Sink de rendu ↓ Interprétation navigateur ↓ Test + monitoring
Décision express
Anti-pattern
“Le champ est validé, donc il est sûr partout.”Correction attendue
“La sortie est en contexte HTML texte, donc autoescape suffit ; si le contexte change, la défense change.”Raison pédagogique
L’exemple illustre le raisonnement de défense, sans fournir de scénario offensif ni de contournement. L’objectif est de reconnaître le mauvais contexte, de choisir l’API sûre et de documenter la correction.
Défenses recommandées
Priorités : supprimer safe/raw injustifiés, remplacer innerHTML par textContent, centraliser le HTML riche, mettre CSP en report-only puis enforcement, durcir cookies, scanner sources/sinks et former les équipes sur les contextes.
Prévenir
- Encodage contextuel.
- APIs textuelles par défaut.
- Sanitizer pour HTML riche.
Réduire l’impact
- CSP stricte.
- Cookies HttpOnly/Secure/SameSite.
- Permissions minimales.
À éviter
- safe/raw non justifié.
- innerHTML avec données non fiables.
- Regex maison pour nettoyer du HTML.
Tableau opérationnel
| Point | Lecture opérationnelle |
|---|---|
| Règle 1 | Encoder à la sortie selon le contexte. |
| Règle 2 | Préférer les APIs textuelles aux APIs HTML. |
| Règle 3 | Sanitizer uniquement pour HTML riche nécessaire. |
| Règle 4 | CSP/Trusted Types comme filets de sécurité. |
| Règle 5 | Tester front, back-office, exports et emails HTML. |
Checklist
- Aucun raw/safe non justifié.
- Aucun innerHTML avec données non fiables.
- HTML riche centralisé et sanitizé.
- CSP active et surveillée.
- Tests XSS intégrés au CI/CD.
Critère de sortie
La zone est considérée maîtrisée lorsque le contexte de rendu est identifié, la défense est contextuelle, les tests confirment l’absence d’interprétation active et les exceptions sont documentées.
| Source | Intérêt |
|---|---|
| OWASP XSS Prevention Cheat Sheet | Règles d’encodage contextuel et recommandations de prévention. |
| OWASP DOM based XSS Prevention Cheat Sheet | Raisonnement sources/sinks et sous-contextes DOM. |
| OWASP Community — Cross Site Scripting | Définition générale et typologie de l’attaque. |
| OWASP Top 10 — A03 Injection | Positionnement XSS dans la famille Injection. |
| PortSwigger Web Security Academy — XSS | Cours et labs de référence sur reflected, stored et DOM XSS. |
| MDN — Cross-site scripting | Explication navigateur et défenses côté plateforme web. |
| MDN — Content Security Policy | Guide CSP et directives de protection. |
| MDN — Trusted Types API | API Trusted Types pour réduire les sinks DOM dangereux. |
| Django Security Documentation | Protection XSS et sécurité intégrée du framework Django. |
| DOMPurify | Sanitizer HTML/SVG/MathML largement utilisé côté client et serveur. |
