← HTTP — sécurité avancée, 40 leçons de cours

Module 20 / 40 · 90 min

20. XSS : données, code et contexte de sortie

Choisir une API de rendu adaptée à chaque destination.

Votre progression apparaîtra ici lorsque JavaScript est actif.

La progression et le meilleur score sont enregistrés uniquement dans ce navigateur. Aucun compte n’est nécessaire ; effacer les données du navigateur les supprime. Les durées de modules sont indicatives et incluent les exercices.

Comprendre le mécanisme

Une XSS apparaît lorsqu’une donnée non fiable est interprétée comme du code dans un contexte de navigateur. Un encodage HTML ne sécurise pas automatiquement une chaîne placée dans JavaScript, une URL ou une feuille de style. La bonne défense commence par éviter les destinations interprétatives inutiles, puis par employer un mécanisme de rendu et une validation adaptés au contexte. La validation d’entrée seule n’exprime pas tous ces contextes de sortie.

Raisonner et vérifier

Pour afficher du texte dans le DOM, textContent préserve son rôle de donnée, contrairement à une insertion HTML libre. Les URL exigent aussi un contrôle de schéma et de destination selon le besoin. Les templates à échappement automatique réduisent le risque tant que leurs sorties sûres ne sont pas abusivement désactivées. Testez les chemins de rendu initiaux et les mises à jour dynamiques, y compris le corrigé et les exports affichés.

Contexte de sortie

L’échappement dépend du contexte de sortie. Chaque contexte a sa syntaxe et ses risques. Le texte HTML, un attribut, une URL et JavaScript ont des règles distinctes. Évitez de réutiliser une chaîne déjà encodée dans un autre contexte sans définir la protection réellement attendue.

Erreur fréquente à comprendre

Un échappement HTML est universel pour JavaScript et URL.

Chaque contexte a sa syntaxe et ses risques.

Texte DOM

textContent traite une chaîne comme du texte. Cette API évite le parsing HTML de cette valeur. textContent place la valeur comme texte sans parser les balises qu’elle contient. C’est adapté à un libellé ; testez le DOM pour vérifier que des chevrons restent visibles et ne créent pas un élément actif.

Erreur fréquente à comprendre

textContent interprète la chaîne comme du HTML actif.

Cette API évite le parsing HTML de cette valeur.

HTML interprété

innerHTML peut être un point d’injection. Cette API demande une politique de contenu adaptée. innerHTML demande au navigateur d’interpréter du balisage. Une donnée non fiable à cette destination exige une politique adaptée ; remplacer des caractères au hasard ne constitue pas une sanitisation complète.

Erreur fréquente à comprendre

innerHTML est sûr pour toute entrée utilisateur.

Cette API demande une politique de contenu adaptée.

CSP complémentaire

Une CSP complète les défenses d’injection. Elle ne corrige pas automatiquement les points d’injection. Une politique CSP peut limiter certaines exécutions ou ressources, mais n’efface pas toutes les conséquences d’une injection. Gardez la séparation données/code et l’encodage adapté comme protections de base.

Erreur fréquente à comprendre

Une CSP remplace toute validation de sortie.

Elle ne corrige pas automatiquement les points d’injection.

Capacités d’origine

Une XSS peut agir sous l’origine compromise. La frontière d’origine ne distingue pas ce script hostile. Une XSS peut lire des données accessibles et agir sous l’origine de la page. Le risque dépasse le seul vol de cookie : actions, accès API et modification d’interface peuvent rester possibles.

Erreur fréquente à comprendre

La SOP neutralise tout script de même origine.

La frontière d’origine ne distingue pas ce script hostile.

HttpOnly limité

HttpOnly limite la lecture du cookie. Le script peut encore déclencher des actions. Même sans lire la valeur du cookie, un script peut envoyer des demandes authentifiées depuis la page. Cet attribut reste utile mais ne rend pas acceptable un point d’injection HTML.

Erreur fréquente à comprendre

HttpOnly supprime toute conséquence d’une XSS.

Le script peut encore déclencher des actions.

Schémas URL

Une URL doit suivre une politique de schémas admis. Le contexte URL demande aussi un contrôle de destination et de schéma. Un attribut href échappé peut encore porter un schéma dangereux ou une destination interdite. Parsez et admettez les schémas et hôtes selon le besoin avant de rendre le lien.

Erreur fréquente à comprendre

Échapper une URL suffit à rendre tout schéma acceptable.

Le contexte URL demande aussi un contrôle de destination et de schéma.

HTML autorisé

Un HTML autorisé demande une sanitisation adaptée. Le stockage ne rend pas sûre une entrée hostile. Si le produit exige du HTML utilisateur, employez un nettoyage maintenu avec une liste d’éléments et attributs admis. Vérifiez le résultat dans le contexte final plutôt qu’un simple retrait de script.

Erreur fréquente à comprendre

Tout HTML stocké en base est automatiquement fiable.

Le stockage ne rend pas sûre une entrée hostile.

Rendu effectif

Les tests doivent vérifier le rendu effectif. L’interprétation par le navigateur détermine le comportement. Des tests sur la chaîne serveur peuvent manquer une interprétation du navigateur. Contrôlez éléments, attributs et comportement dans le DOM avec données factices contenant guillemets, chevrons et URL non admise.

Erreur fréquente à comprendre

Une chaîne présente dans le code suffit à prouver une exécution.

L’interprétation par le navigateur détermine le comportement.

Données et code

Les données et le code doivent être séparés. La construction de code avec des données non fiables crée un risque. Préférez des API structurées et des valeurs passées comme données. Construire du JavaScript ou des handlers HTML par concaténation multiplie les contextes d’échappement et rend la preuve de sécurité fragile.

Erreur fréquente à comprendre

Concaténer des entrées dans du JavaScript est toujours sûr.

La construction de code avec des données non fiables crée un risque.

Atelier guidé : lire, expliquer et vérifier le code

const value = '<img src=x onerror=alert(1)>';
const label = document.createElement('div');
label.textContent = value;

La valeur ressemble à une balise avec un gestionnaire, mais textContent la conserve comme texte. Le navigateur ne doit donc pas créer l’image active de cette chaîne dans ce div. Inspectez le DOM puis comparez avec un laboratoire isolé de parsing HTML, sans utiliser de données réelles.

Le contrôle est local à cette affectation. Cette API ne parse pas la valeur comme du HTML. Ce serait une autre sémantique de sink HTML. La création de texte ne réalise pas cet appel.

Travail pratique : Affichez une note de laboratoire contenant des chevrons, guillemets et caractères Unicode dans le rendu initial puis dans une mise à jour DOM.

Critères de correction : Vérifiez le texte attendu et l’absence de nouveaux éléments ou gestionnaires d’événements interprétés. Inspectez chaque destination de données ; remplacez les insertions HTML inutiles et testez séparément les URL permises.

Libellé DOM : conserver le texte comme texte

Le besoin fonctionnel est d’afficher un libellé, donc aucune balise n’a besoin d’être interprétée. innerHTML donne pourtant au navigateur un contexte de parsing HTML. Une valeur reçue peut alors créer des éléments et attributs actifs au lieu de rester une simple chaîne visible.

Affectez la valeur à textContent sur l’élément prévu. Une chaîne contenant des chevrons ou des guillemets s’affiche alors comme texte, sans devenir le balisage décrit par ces caractères. Ne pré-encodez pas arbitrairement une valeur avant textContent, au risque d’afficher des entités littérales ou de mélanger les contrats.

Testez le DOM obtenu : texte exact et absence d’élément enfant provenant de la valeur. Si un autre produit exige du HTML enrichi, il doit disposer d’un parcours différent avec nettoyage maintenu et politique précise. CSP et HttpOnly restent utiles mais ne remplacent pas le bon choix de destination pour ce libellé.

Points de vigilance : textContent insère du texte, sans analyser des balises ni des attributs événementiels. Une liste noire partielle manque d’autres constructions et contextes dangereux. HttpOnly limite la lecture d’un cookie, pas les actions qu’un script injecté peut effectuer. Un encodage URL n’est pas le contrat d’insertion du texte dans le DOM.

Documentation de référence ↗

Exemple commenté

const title = document.querySelector("[data-lab-title]");
title.textContent = userSuppliedLabel;

userSuppliedLabel reste ici du texte dans cet élément. Cet exemple n’autorise pas à placer la même valeur librement dans une URL ou du JavaScript.

Exercice de mise en pratique

Affichez une note de laboratoire contenant des chevrons, guillemets et caractères Unicode dans le rendu initial puis dans une mise à jour DOM.

Voir une proposition de correction

Vérifiez le texte attendu et l’absence de nouveaux éléments ou gestionnaires d’événements interprétés. Inspectez chaque destination de données ; remplacez les insertions HTML inutiles et testez séparément les URL permises.

Points de vérification

  • Identifier la destination exacte.
  • Préférer les API de texte.
  • Ne pas désactiver l’échappement pour corriger la mise en page.

Contrôle de connaissances

Cours associé : 20. XSS : données, code et contexte de sortie ↗
Quel mécanisme convient à un libellé qui doit rester du texte dans un élément DOM ?

Documentation de référence ↗

Validation du module

101 questions, objectif pédagogique de 75 %. Durée conseillée de 150 minutes, sans limite imposée. Les questions et les choix sont mélangés ; le corrigé apparaît après validation. Le contrôle rapide de la leçon et l’examen final du cours restent des exercices distincts.

Commencer ou reprendre les 101 questions →