Si un visiteur peut déposer sur votre page un texte que d'autres verront, et que ce texte n'est pas échappé, il peut y déposer un script à la place. Celui-ci tourne au nom de votre site, avec la session de votre visiteur, et peut tout ce que ce visiteur peut faire.
D'où cela vient
- Un commentaire, un nom, un avis - tout ce qu'une personne tape et qu'une autre voit.
- Un paramètre d'URL réimprimé sur la page, c'est-à-dire le champ de recherche de presque tous les sites.
- Le nom d'un fichier déposé.
- Des données venues d'une API que vous ne maîtrisez pas.
L'habitude
Échappez à la SORTIE, chaque fois, dans le contexte où vous écrivez. Pas à l'entrée : la même donnée peut être imprimée dans du HTML, dans un attribut et dans du JavaScript, et chacun demande un échappement différent.
echo htmlspecialchars($name, ENT_QUOTES, 'UTF-8');
- Dans du texte HTML - htmlspecialchars avec ENT_QUOTES.
- Dans un attribut - la même chose, et mettez toujours l'attribut entre guillemets.
- Dans du JavaScript - json_encode, jamais de concaténation de chaînes.
- Dans une URL - urlencode.
Une deuxième couche
add_header Content-Security-Policy "default-src 'self'; script-src 'self'" always;
La CSP dit au navigateur de n'exécuter des scripts que depuis votre propre origine : un script en ligne injecté ne s'exécute donc pas, même si l'un passe. Mettez-la d'abord en mode rapport seul, sinon vous casserez votre propre page.
Testez-le
Mettez un marqueur inoffensif dans chaque champ et regardez la SOURCE de la page qui l'affiche. Voir votre marqueur comme du texte est correct ; le voir comme une balise, c'est la faille.
