cybercursus

Se protéger : échappement, CSP, sanitisation

11 min · Débutant · 7 août 2026

Sommaire
  1. Première ligne de défense : l’échappement contextuel
  2. Préférer textContent à innerHTML
  3. Deuxième ligne de défense : une CSP stricte
  4. Troisième cas : quand du HTML doit vraiment être autorisé

Première ligne de défense : l’échappement contextuel

La protection de fond contre toutes les familles de XSS vues dans ce cours consiste à échapper toute donnée non fiable avant de l’insérer dans une page : remplacer les caractères qui ont un sens spécial en HTML par leur équivalent inoffensif.

text
< devient &lt;
> devient &gt;
" devient &quot;
' devient &#39;
& devient &amp;

Une fois échappée, une charge comme <img src=x onerror=...> s’affiche comme du texte littéral, jamais comme une balise active. Le détail qui compte : le contexte d’insertion change les règles. Échapper pour un contexte HTML ne protège pas un contexte JavaScript ou un attribut d’URL, qui ont chacun leurs propres caractères sensibles.

Préférer textContent à innerHTML

Le réflexe le plus direct, quand aucun HTML n’a besoin d’être inséré : ne jamais utiliser innerHTML pour du texte simple. textContent ne réalise strictement aucune interprétation HTML, quel que soit son contenu.

html
<!-- HTML -->
<input type="text" id="champ" placeholder="Tape ici..." style="width:100%;box-sizing:border-box;padding:6px;" />
<div id="resultat" style="margin-top:10px;"></div>

// JS
document.getElementById('champ').addEventListener('input', function (e) {
// Correction : textContent insere du texte brut, jamais interprete comme du HTML
document.getElementById('resultat').textContent = e.target.value;
});

Tape exactement la même charge qu’au chapitre sur la XSS DOM-based (<img src=x onerror="console.log('XSS DOM executee')">) : elle s’affiche cette fois telle quelle, comme texte visible, sans jamais s’exécuter.

Astuce

Ce bac à sable utilise le même code HTML que celui du chapitre sur la XSS DOM-based, avec une seule ligne modifiée (textContent au lieu de innerHTML). C’est souvent tout ce qu’il faut corriger, une fois le sink dangereux identifié.

Deuxième ligne de défense : une CSP stricte

Le cours sur HTTP a introduit l’en-tête Content-Security-Policy. Appliquée à la XSS, une CSP stricte (sans la directive 'unsafe-inline') empêche l’exécution de tout script ou gestionnaire d’évènement inline, y compris <script>...</script> et onerror="...", exactement les techniques utilisées dans les démonstrations de ce cours.

Info

Une CSP correctement configurée aurait bloqué chacune des démonstrations de ce cours, malgré l’absence d’échappement. C’est pour ça qu’elle est présentée comme une seconde ligne de défense : elle limite les dégâts d’une erreur d’échappement, elle ne dispense jamais de corriger cette erreur.

Troisième cas : quand du HTML doit vraiment être autorisé

Un champ de commentaire qui autorise du gras ou de l’italique ne peut pas se contenter d’échapper tout le HTML : il doit sanitiser, c’est-à-dire ne conserver qu’une liste explicite de balises et d’attributs jugés sûrs (une allowlist), et rejeter tout le reste. Écrire soi-même une liste de balises à bloquer est une erreur classique : la liste est presque toujours incomplète, exactement comme pour la validation d’entrée contre les injections SQL. Utiliser une bibliothèque de sanitisation éprouvée reste la seule approche fiable dans ce cas.

Pourquoi textContent élimine-t-il une XSS là où innerHTML l'exposait ?
Que change une Content-Security-Policy stricte (sans 'unsafe-inline') face à une charge XSS qui a quand même atteint la page ?

Pour aller plus loin

Commentaires

Recherche