Kodokon kodokon.com

Sécurité côté HTML : XSS, sandbox, noopener et CSP

Identifiez les vecteurs XSS propres au balisage et déployez les défenses natives du HTML : sandbox, noopener et Content Security Policy.

11 min · 3 questions

Ouvrir cette leçon dans Kodokon

Le contexte d'échappement fait toute la différence : une valeur inoffensive dans un nœud texte devient exécutable dans un attribut. L'attribut non quoté est le pire des cas : une simple espace dans la donnée injectée suffit à créer un nouvel attribut, par exemple un gestionnaire onmouseover. Même correctement quotée, une valeur reste dangereuse dans les sinks sensibles : href et src acceptent le schéma javascript:, formaction détourne la soumission d'un formulaire, et srcdoc interprète comme du HTML ses entités une fois décodées.

HTML
<!-- userName = x onmouseover=alert(1) -->
<img src="avatar.png" alt=x onmouseover=alert(1)>
<!-- L'attribut non quoté laisse entrer un handler -->
Une donnée non échappée dans un attribut non quoté devient du code.

L'attribut sandbox d'une iframe retire tous les privilèges, puis vous en réaccordez à la carte : allow-scripts, allow-forms, allow-popups... Sans allow-same-origin, le document embarqué reçoit une origine opaque : pas de cookies, pas de storage, aucun accès au DOM parent - même s'il est servi depuis votre propre domaine.

HTML
<iframe
  src="https://widget.example.com"
  sandbox="allow-scripts allow-forms"
  referrerpolicy="no-referrer">
</iframe>
Un widget tiers scriptable, mais confiné dans une origine opaque.

Un lien target=_blank donnait historiquement à la page ouverte une référence window.opener vers votre onglet : elle pouvait rediriger votre page vers un clone de phishing, l'attaque dite de tabnabbing. Les navigateurs modernes appliquent désormais noopener implicitement sur target=_blank, mais l'expliciter reste indispensable pour window.open en JavaScript et pour documenter l'intention ; ajoutez noreferrer pour supprimer aussi l'en-tête Referer.

HTML
<a href="https://external.example"
   target="_blank"
   rel="noopener noreferrer">
  Consulter la ressource externe
</a>
La page ouverte reçoit window.opener === null.

Une Content Security Policy limite les sources de code exécutable et neutralise la plupart des XSS, même lorsque l'injection a réussi. Déclarée via une balise <meta http-equiv>, elle comporte toutefois des angles morts : les directives frame-ancestors, report-uri et sandbox y sont ignorées et exigent l'en-tête HTTP. Préférez les nonces régénérés à chaque réponse aux listes de domaines, que la directive strict-dynamic rend d'ailleurs obsolètes.

HTML
<meta http-equiv="Content-Security-Policy"
      content="default-src 'self';
               script-src 'self' 'nonce-r4nd0m'">
Seuls les scripts portant le nonce du serveur s'exécutent.

Quiz de validation

Vérifiez que vous avez bien retenu les points clés de cette leçon.

  1. Pourquoi combiner allow-scripts et allow-same-origin sur une iframe de même origine annule-t-il le sandbox ?
    • Le document embarqué, scriptable et non isolé, peut atteindre le DOM parent et retirer lui-même l'attribut sandbox
    • Les deux jetons sont incompatibles et le navigateur ignore l'attribut entier
    • allow-same-origin désactive automatiquement tous les autres jetons
  2. Contre quelle attaque rel=noopener protège-t-il ?
    • Le vol des cookies de session par la page ouverte
    • L'injection de scripts dans la page ouverte
    • Le tabnabbing : la page ouverte utilise window.opener pour rediriger votre onglet vers un site de phishing
  3. Quelle directive est ignorée quand la CSP est déclarée via <meta http-equiv> ?
    • script-src
    • frame-ancestors
    • default-src
    • img-src