Plusieurs politiques CSP sur une même page
CentralCSP Team ·
Dernière mise à jour:
Vous pouvez envoyer plusieurs politiques de sécurité du contenu (CSP) à une même page, et le navigateur les respecte toutes en même temps. Une CSP est un header de réponse HTTP qui indique au navigateur quels scripts, styles et autres ressources une page a le droit de charger. Quand une page en porte plusieurs, le navigateur ne les fusionne pas en une seule politique. Il vérifie chacune indépendamment, et une ressource doit passer toutes les politiques pour se charger.
Cette seule règle explique presque tout du fonctionnement des politiques multiples : ajouter une politique ne peut que rendre une page plus stricte, jamais plus permissive. Un deuxième header ne peut pas réautoriser ce que le premier a bloqué. Cet article montre comment les politiques se combinent, les pièges qui surprennent, et comment tester une politique plus stricte en toute sécurité avant de l'appliquer.
Comment un navigateur combine plusieurs politiques
Une page peut récupérer des politiques depuis plusieurs sources en même temps :
- Plusieurs headers de réponse HTTP
Content-Security-Policy. - Un seul header
Content-Security-Policyqui contient plusieurs politiques séparées par des virgules. Chaque segment séparé par une virgule compte comme une politique à part entière. - Un élément
<meta http-equiv="Content-Security-Policy">, appliqué en plus des headers. - Un ou plusieurs headers
Content-Security-Policy-Report-Only, qui signalent les violations mais ne bloquent jamais.
Le navigateur rassemble toutes les politiques actives dans une seule liste et les évalue indépendamment. Pour une requête donnée, il part de l'état « autorisé », puis parcourt la liste. Si une politique appliquée est violée, la requête est bloquée, et rien, plus loin dans la liste, ne peut la réautoriser. C'est le mécanisme derrière la formule qu'on entend souvent : « la politique la plus restrictive l'emporte ».
Les politiques Report-Only sont ignorées lors de cette décision de blocage. Elles ne sont évaluées que pour produire des reports, donc elles influencent ce que vous voyez dans votre monitoring, pas ce que le navigateur charge réellement.
Une ressource doit satisfaire chaque politique
Voici l'exemple canonique, deux headers Content-Security-Policy sur la même réponse :
Content-Security-Policy: default-src 'self' http://example.com;
connect-src 'none';Content-Security-Policy: connect-src http://example.com/;
script-src http://example.com/Le deuxième header indique connect-src http://example.com/, donc à lui seul il autoriserait cette connexion. Cela n'a aucune importance. La première politique fixe connect-src 'none', et la requête doit passer les deux. Comme une politique interdit toutes les connexions, la connexion est bloquée, et la règle effective pour connect-src est 'none'.
MDN décrit la combinaison de la même manière : ajouter des politiques « ne peut que restreindre davantage les capacités de la ressource protégée ». Aucune deuxième politique ne peut assouplir la première.
L'ordre des headers ne change pas le résultat. Que connect-src 'none' arrive en premier ou en second, le résultat est identique, parce que chaque politique est vérifiée indépendamment et que la requête doit toutes les franchir.
Le piège de l'intersection avec les allowlists d'hôtes
La règle « passer chaque politique » réserve une mauvaise surprise quand deux politiques autorisent des ensembles d'hôtes qui se recoupent sans se confondre. On s'attend à ce que le navigateur prenne l'union des hôtes. Il fait l'inverse.
Content-Security-Policy: script-src 'self' https://trusted.com https://analytics.comContent-Security-Policy: script-src 'self' https://trusted.comUn script depuis https://analytics.com passe la première politique mais échoue à la deuxième, donc il est bloqué. Un script depuis https://trusted.com passe les deux, donc il se charge. Le résultat effectif est l'intersection des deux allowlists, 'self' et https://trusted.com, parce qu'une ressource doit satisfaire chaque politique individuellement.
L'accident est vite arrivé. Si une équipe ajoute une CSP sur le CDN ou le proxy et qu'une autre en ajoute une dans l'application, un hôte que seule l'une des deux autorise se retrouve bloqué. Quand une ressource est autorisée par une politique mais pas par l'autre, elle ne se charge pas, point final. Si vous déboguez une ressource qui « devrait » être autorisée, vérifiez si une deuxième politique est en jeu avant de toucher à la directive que vous examiniez.
Le navigateur résout le fallback default-src politique par politique, avant la vérification entre politiques. Il ne construit jamais une politique fusionnée unique, donc le fallback d'une directive dans la politique A n'a aucun effet sur la politique B.
Pour une page qui a besoin d'une politique claire et maintenable, regroupez tout dans un seul header bien structuré plutôt que de disperser les directives entre plusieurs. Notre évaluateur CSP signale les directives faibles ou contradictoires pour que vous voyiez la vraie politique effective avant de la déployer.
Tester une politique plus stricte sans casser la page
La raison la plus utile de faire tourner plusieurs politiques, c'est d'appliquer ce qui fonctionne aujourd'hui tout en testant quelque chose de plus serré. Vous appliquez une politique et laissez la plus stricte tourner en Report-Only en parallèle :
Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.comContent-Security-Policy-Report-Only: default-src 'self'; script-src 'self'Les scripts depuis https://trusted.com se chargent toujours, parce que la politique appliquée les autorise. La politique Report-Only est plus stricte, donc le navigateur envoie aussi un report de violation pour chacun de ces scripts, sans rien bloquer. Vous lisez ces reports, confirmez que la politique plus stricte ne casserait pas la page, puis vous la promouvez dans le header appliqué.
Pour collecter les reports, pointez la politique vers un endpoint de reporting. Envoyez un header Reporting-Endpoints et référencez-le depuis la directive report-to dans chaque politique :
Reporting-Endpoints: csp-endpoint="https://<Endpoint-ID>.report.centralcsp.com"Content-Security-Policy: default-src 'self'; script-src 'self' https://trusted.com; report-to csp-endpointContent-Security-Policy-Report-Only: default-src 'self'; script-src 'self'; report-to csp-endpointUn point à anticiper : une requête produit un report par politique appliquée qu'elle viole. Si vous faites tourner plusieurs politiques et qu'une seule ressource bloquée en viole deux, vous obtenez deux reports pour ce seul blocage. C'est attendu, puisque le navigateur signale par politique, mais cela signifie que votre volume brut de reports croît avec le nombre de politiques, pas avec le nombre de problèmes distincts. Regrouper les reports par ressource et par directive, plutôt que de compter les événements bruts, limite le bruit. C'est le genre de corrélation que CentralCSP fait pour vous, pour que l'essai en Report-Only se lise comme une courte liste de changements à faire, et non comme un flot d'événements en double.
Ce qu'il faut retenir
- Plusieurs politiques sont appliquées indépendamment. Une ressource doit toutes les passer pour se charger.
- Une politique supplémentaire ne peut qu'ajouter des restrictions. Elle ne peut jamais réautoriser ce qu'une autre politique a bloqué.
- Les allowlists d'hôtes qui se recoupent se réduisent à leur intersection. Un hôte autorisé par une seule politique reste bloqué.
- L'ordre des headers n'a pas d'importance.
- Report-Only ne bloque jamais, c'est donc le moyen sûr de tester une politique plus stricte à côté d'une politique qui fonctionne.
- Une seule ressource bloquée peut produire un report par politique violée.
Ce comportement fait partie de CSP Level 3 et fonctionne dans tout navigateur qui prend en charge CSP. Pour prendre de l'avance, scannez votre configuration actuelle avec le scanner CSP gratuit et voyez comment vos politiques se combinent avant de changer quoi que ce soit.
Pour en savoir plus sur les briques de base derrière ces exemples, voir comment construire une CSP solide et démarrer avec le reporting CSP.