Articlepar DevBlog

Comprendre la CSP pas à pas

La Content Security Policy expliquée simplement : directives, pièges de unsafe-inline, nonces, et pourquoi les pages statiques changent la donne.

  • #securite
  • #csp
  • #web
  • #headers

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

DirectiveRôle
default-srcValeur de repli pour toutes les autres
script-srcOrigine des scripts
style-srcOrigine des feuilles de style
img-srcOrigine des images
connect-srcfetch, XHR, WebSocket
object-srcPlugins (à mettre à 'none')
frame-ancestorsQui peut intégrer votre page dans une iframe
base-uriValeurs 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.

html
<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

  1. Commencez en Content-Security-Policy-Report-Only : le navigateur signale les violations sans rien bloquer.
  2. Corrigez ce qui est signalé.
  3. Passez à l'en-tête réel.
  4. 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-eval en production.
  • Une CSP complète l'échappement des données, elle ne le remplace pas.
  • Mesurez avant d'imposer : le mode Report-Only est là pour ça.