CSP outils
Content-Security-Policy en pratique : ce que gouverne chaque directive, comment les nonces, les empreintes et les expressions de source correspondent, et comment déployer une politique avec Report-Only.
1 outils
Ce qu’est réellement une politique
Content-Security-Policy est un en-tête de réponse composé de directives, chacune
contenant une liste d’expressions de source. Avant que le navigateur ne charge une
sous-ressource, n’exécute du code en ligne, ne soumette un formulaire ou ne laisse la
page être encadrée, il consulte la directive compétente ; si rien ne correspond, la
requête n’a jamais lieu et une violation est rapportée. L’application se fait dans le
navigateur, et une politique ne retire que des capacités, elle n’en accorde jamais.
La correspondance travaille sur les origines — schéma, hôte, port — et non sur l’URL
que vous aviez en tête : 'self' sur https://app.example.com ne couvre ni
https://cdn.example.com ni ses sous-domaines. Une politique ne vaut par ailleurs que
son échappatoire la plus faible : script-src 'self' 'unsafe-inline' livre à
quiconque peut injecter du balisage une balise de script fonctionnelle — l’attaque
même que la CSP existe pour arrêter. Remplacez 'unsafe-inline' par un nonce par
réponse ou une empreinte de contenu.
Les politiques se composent par intersection, jamais par union : quand une réponse
porte deux en-têtes Content-Security-Policy — le vôtre plus celui qu’un CDN a
ajouté — une ressource doit satisfaire les deux, si bien qu’un en-tête supplémentaire
ne fait que resserrer la page.
Référence des directives
| Directive | Gouverne | Repli sur default-src ? |
|---|---|---|
script-src | éléments script, eval, gestionnaires en ligne | oui |
style-src | éléments style, liens de feuilles de style, @import, attributs style | oui |
connect-src | fetch, XMLHttpRequest, WebSocket, EventSource, sendBeacon | oui |
img-src / font-src / media-src / manifest-src | images et srcset ; polices web ; audio, vidéo, track ; manifeste d’application | oui |
object-src | object et embed — toujours 'none' | oui |
frame-src / child-src / worker-src | documents imbriqués ; workers | oui, les workers via child-src |
base-uri / form-action | valeurs qu’une balise base peut fixer ; où les formulaires peuvent soumettre | non |
frame-ancestors | qui peut intégrer cette page ; supplante X-Frame-Options | non |
sandbox / require-trusted-types-for | drapeaux de bac à sable sur ce document ; puits de XSS DOM | non |
report-uri / report-to | où les rapports de violation sont envoyés en POST | non |
La colonne de droite est le piège : default-src 'self' laisse encore ouverts le
détournement de la balise base, l’exfiltration par formulaire et le détournement de
clic. script-src-elem et script-src-attr séparent les éléments des gestionnaires
en ligne.
Expressions de source
| Expression | Correspond à | À surveiller |
|---|---|---|
'self' / 'none' | le schéma, l’hôte et le port exacts du document / rien | pas les sous-domaines ; 'none' est nul à côté de toute autre valeur |
https: | n’importe quel hôte sur ce schéma | chaque CDN d’internet |
https://cdn.example.com | cette origine, port par défaut implicite | les préfixes de chemin ne sont pas appliqués à travers les redirections |
*.example.com / * | n’importe quel sous-domaine, à toute profondeur / n’importe quel hôte | pas example.com nu ; * exclut data: et blob: |
'nonce-…' | les éléments portant l’attribut nonce correspondant | 128 bits aléatoires ou plus, frais à chaque réponse |
'sha256-…' | le code en ligne dont les octets exacts produisent cette empreinte | un octet d’espace change l’empreinte |
'strict-dynamic' | les scripts créés par un script déjà approuvé | les sources d’hôte et de schéma deviennent ignorées |
'unsafe-inline' | tout script ou style en ligne | ignoré dès qu’un nonce ou une empreinte est présent |
'unsafe-eval' / 'unsafe-hashes' | eval et new Function / empreintes sur onclick, style | 'wasm-unsafe-eval' en est la version restreinte |
Déployer avec Report-Only
Livrez la politique candidate comme Content-Security-Policy-Report-Only : évaluée
à l’identique, ne bloquant rien, et servable à côté d’une politique appliquée, ce qui
permet d’en resserrer une seconde pendant que celle en vigueur protège les
utilisateurs. Collectez les violations avec report-uri /csp-reports (déprécié,
universellement pris en charge) ou report-to, qui exige un en-tête
Reporting-Endpoints ; la livraison des rapports est exemptée de connect-src. Les
blocages multi-origines se réduisent à une origine dans blocked-uri, nommant l’hôte
refusé, pas le fichier ; ajoutez 'report-sample' pour un extrait de code et
regroupez par effective-directive.
Quel outil pour quel travail
Quand un site est en ligne, la question est quelle politique est réellement
livrée. En-têtes HTTP charge l’URL depuis api.sitekits.dev et
renvoie le statut, le nombre de redirections et chaque en-tête de réponse, jamais le
corps — ce qui révèle un proxy ayant réécrit votre politique. Les adresses internes
sont refusées par sa protection SSRF.
Si vous en êtes plutôt à la rédaction, le
Générateur CSP offre 14 champs de directives par-dessus une
base durcie default-src 'self'; frame-ancestors 'none'; base-uri 'self'; object-src 'none', plus une case upgrade-insecure-requests active par défaut — un
formulaire non modifié émet donc déjà cette base avec
upgrade-insecure-requests ajouté. La chaîne est reconstruite au fil de la saisie,
dans le navigateur. Les directives hors de ces champs (report-to, sandbox,
require-trusted-types-for) s’ajoutent à la main.
Établir la liste d’autorisation d’une application existante est un problème
d’inventaire : exportez un HAR depuis DevTools, lisez-le dans la
Visionneuse HAR, puis passez les URL surprenantes dans le
Parseur d’URL pour réduire chacune à la forme schéma-hôte-port
qu’une expression de source exige. Assainissez avec le
Nettoyeur HAR avant de le joindre à un ticket — les HAR portent
des cookies et des en-têtes Authorization. Le
Diff de Texte montre ce qui a changé entre les versions
report-only et appliquée ; le Formateur JSON rend lisible une
charge utile csp-report ; et le Testeur REST API appelle
votre cible directement depuis le navigateur, sans serveur sitekits sur le chemin —
et sous la politique de sa page, qui assouplit connect-src à 'self' https:, pas
sous la vôtre. Un appel qui réussit là mais échoue dans votre application désigne
votre propre en-tête. Il ne nommera pas la cause : un blocage connect-src et un
rejet CORS se manifestent tous deux par une unique TypeError de fetch, et l’outil
imprime un seul message couvrant les deux. Également :
hub HTTP, hub sécurité,
outils de l’ingénieur sécurité.
Casses courantes
Ajouter un nonce désactive silencieusement 'unsafe-inline'
Les gestionnaires de balises et les widgets de discussion qui injectent leurs propres
balises de script cessent de s’exécuter, puisqu’ils ne voient jamais votre valeur par
réponse ; 'strict-dynamic' est le remède.
Les empreintes CSP sont du base64 du condensé, pas de l’hexadécimal
'sha256-…' attend du base64 des 32 octets bruts du condensé : de l’hexadécimal issu
du Générateur de Hash puis passé dans Base64 donne
donc une chaîne erronée. Copiez-la depuis l’erreur affichée dans la console du
navigateur.
Un nonce codé en dur, c’est 'unsafe-inline' avec des étapes en plus
Les nonces doivent être régénérés à chaque réponse, ce qui les rend côté serveur ; une constante dans un gabarit — ou du HTML mis en cache en périphérie tandis que l’en-tête se régénère — est devinable. Le Générateur UUID convient pour des essais manuels locaux, jamais pour un déploiement.
Une politique en balise meta ne peut pas exprimer la moitié de la CSP
frame-ancestors, sandbox, report-uri et Report-Only sont ignorés dans
meta http-equiv, et la politique ne couvre que le balisage qui la suit.