Pourquoi une CSP ?
Une Content Security Policy est un en-tête HTTP qui dit au navigateur d'où il a le droit de charger scripts, styles, images et polices. Même si un attaquant parvient à injecter du HTML, le navigateur refusera d'exécuter ce qui ne vient pas d'une source autorisée.
C'est une seconde ligne de défense : elle ne remplace pas l'échappement des données, elle limite les dégâts quand celui-ci échoue.
Les directives essentielles
| Directive | Rôle |
|---|---|
default-src | Valeur de repli pour toutes les autres |
script-src | Origine des scripts |
style-src | Origine des feuilles de style |
img-src | Origine des images |
connect-src | fetch, XHR, WebSocket |
object-src | Plugins (à mettre à 'none') |
frame-ancestors | Qui peut intégrer votre page dans une iframe |
base-uri | Valeurs autorisées pour <base> |
Une politique de départ raisonnable :
default-src 'self';
object-src 'none';
frame-ancestors 'none';
base-uri 'self';
form-action 'self'Le piège de unsafe-inline
Autoriser 'unsafe-inline' dans script-src permet d'exécuter n'importe quel script en ligne, y compris celui qu'un attaquant aurait injecté. La protection contre le XSS devient alors quasi nulle.
La solution classique est le nonce : un jeton aléatoire généré à chaque requête, placé dans l'en-tête et dans l'attribut nonce des scripts légitimes.
<script nonce="r4nd0m-par-requete">
console.log("autorisé");
</script>Nonce ou pages statiques ?
Un nonce doit changer à chaque requête. Cela suppose que la page soit générée à la demande. Or une page prérendue au build est la même pour tout le monde : impossible d'y injecter un nonce valide.
Il faut donc arbitrer :
- Pages dynamiques + nonce : meilleure protection, mais rendu à chaque requête.
- Pages statiques +
'unsafe-inline': performances maximales, protection moindre sur les scripts en ligne.
Ce blog a choisi les pages statiques. La compensation : aucune source tierce autorisée, pas de HTML brut dans le Markdown, et un contenu maîtrisé.
Déployer sans casser
- Commencez en
Content-Security-Policy-Report-Only: le navigateur signale les violations sans rien bloquer. - Corrigez ce qui est signalé.
- Passez à l'en-tête réel.
- Testez en continu : un test e2e qui échoue à la moindre violation de CSP évite les régressions.
À retenir
- Partez de
default-src 'self'et ouvrez au strict nécessaire. - Évitez
unsafe-evalen production. - Une CSP complète l'échappement des données, elle ne le remplace pas.
- Mesurez avant d'imposer : le mode
Report-Onlyest là pour ça.