Tous les articles

Comment les mots-clés CSP report-sha révèlent chaque script chargé

CentralCSP Team ·

Dernière mise à jour:

Vous pouvez demander au navigateur de vous indiquer le hash cryptographique de chaque script qui se charge sur une page. Les mots-clés de la politique de sécurité du contenu (CSP) 'report-sha256', 'report-sha384' et 'report-sha512' font exactement cela : ajoutez-en un à une directive de script, pointez la politique vers un endpoint de reporting, et chaque chargement de script produit un rapport transportant le digest du script. Aucun script n'est bloqué. Vous obtenez un enregistrement précis et continu de ce qui s'exécute côté client, ce qui est la matière première d'un inventaire de scripts.

C'est un ajout récent, mené par Chromium (Chrome et les autres navigateurs Chromium), avec des travaux WebKit en cours et pas encore de prise en charge Firefox. Il n'est pas sur MDN au moment où nous écrivons, donc traitez-le comme une fonctionnalité émergente, pas comme une fonctionnalité multi-navigateurs stable.

Ce que font les mots-clés report-sha

Les mots-clés sont des valeurs de source que vous placez dans une directive de script telle que script-src ou script-src-elem, aux côtés des autres mots-clés CSP que vous utilisez déjà :

  • 'report-sha256' rapporte chaque script avec un digest SHA-256
  • 'report-sha384' rapporte chaque script avec un digest SHA-384
  • 'report-sha512' rapporte chaque script avec un digest SHA-512

Ils n'autorisent ni ne bloquent rien. Un digest dans un rapport relève de la seule observabilité, distinct des sources de hash appliquées (la forme 'sha256-...') que vous utilisez pour autoriser un script inline ou externe précis ; voir comment générer un hash CSP pour produire ces derniers. Quand l'un de ces mots-clés report-sha est présent et qu'une ressource de type script est récupérée, le navigateur calcule le digest de la réponse et envoie un rapport à l'endpoint de la politique.

Le but, c'est l'inventaire. La CSP vous dit généralement ce qui a été bloqué. Ces mots-clés vous disent ce qui s'est chargé, avec un digest que vous pouvez rapprocher de fichiers connus, pour qu'un backend construise un inventaire de scripts ou une nomenclature logicielle (SBOM) et remarque quand un script change.

Mettez-le en place

Le reporting passe par la directive report-to, qui nomme un groupe déclaré dans le header Reporting-Endpoints. L'ancienne directive report-uri n'est pas utilisée par cette fonctionnalité, et la différence entre report-uri et report-to explique pourquoi. Si vous n'avez pas encore câblé le reporting, suivez d'abord comment configurer le Reporting API du navigateur.

Voici la mise en place minimale qui fonctionne. Déclarez un groupe d'endpoint, puis ajoutez le mot-clé et pointez la politique vers le groupe :

Reporting-Endpoints: hashes-endpoint="https://<Endpoint-ID>.report.centralcsp.com"
Content-Security-Policy: script-src 'self' 'report-sha256';
                         report-to hashes-endpoint

L'endpoint doit être en HTTPS. Comme tout endpoint du Reporting API, une URL non sécurisée est ignorée.

Pour collecter les digests sans aucun risque de casser la page, démarrez en mode report-only avec le header Content-Security-Policy-Report-Only. Vous rassemblez d'abord le véritable inventaire de scripts, puis vous resserrez la politique appliquée une fois que vous savez ce qui se charge. La même approche par étapes est traitée dans comment construire une CSP solide et démarrer avec le reporting CSP.

À quoi ressemble le rapport

Les rapports arrivent dans l'enveloppe standard du Reporting API : un tableau JSON envoyé avec Content-Type: application/reports+json. Le type de rapport externe pour cette fonctionnalité est "csp-hash".

Le corps du rapport transporte l'identité et le digest du script. D'après la spec CSP Level 3, le corps possède ces champs :

{
  "documentURL": "https://mywebsite.com/",
  "subresourceURL": "https://mywebsite.com/my_script.js",
  "hash": "sha256-r2hRGID3tnFVlAI+bMCPMjaKx/ovuqgaMic09dPqVCw=",
  "destination": "script",
  "type": "subresource"
}

Deux valeurs de type se situent à des niveaux différents, gardez-les donc distinctes. Le type de rapport externe du Reporting API est "csp-hash". Le corps interne a son propre type, montré comme "subresource" dans l'exemple de la spec. Le champ hash est formaté comme <algorithm>-<base64>, la même forme que vous utiliseriez comme source de hash dans une politique.

Chromium émet le corps en camelCase exactement comme montré ci-dessus (documentURL, subresourceURL, hash, type, destination), enveloppé dans l'enveloppe standard du Reporting API qui ajoute type, url, user_agent et age autour. L'exemple de la spec CSP Level 3 sérialise le corps en snake_case (document_url, subresource_url), mais la forme livrée par Chromium est en camelCase.

Comportement et pièges

Quelques points valent la peine d'être connus avant de vous y fier.

  • Endpoint uniquement, pas in-page. Les rapports csp-hash ne sont pas livrés à un ReportingObserver in-page ; ils vont uniquement vers votre endpoint serveur. Cela diffère des rapports de violation CSP classiques, que Chromium achemine bien vers un ReportingObserver.
  • Comportement en report-only. Les mots-clés report-sha collectent les hashs pour le reporting, que la politique environnante soit appliquée ou en report-only, car l'algorithme ne dépend pas de l'application.
  • Les scripts cross-origin nécessitent CORS. Pour un script chargé depuis une autre origine, le navigateur ne peut calculer et inclure le digest que si la requête a été faite en mode CORS. Ajoutez crossorigin="anonymous" à la balise pour que le navigateur puisse lire le corps de la réponse. Sans cela, le hash de ce script externe peut manquer.
<script
  src="https://cdn.example.com/app.js"
  crossorigin="anonymous"></script>
  • Combiner les algorithmes. Le fait que les trois mots-clés puissent être définis en même temps pour obtenir plusieurs digests par script, et la façon dont un mot-clé report-sha interagit avec une source de hash appliquée dans la même directive, n'est pas précisé dans la spec, testez-le donc dans votre propre configuration avant de vous y fier.

Ne confondez pas ces mots-clés de reporting avec les mots-clés d'application distincts 'url-sha256-...' et 'eval-sha256-...'. Ces derniers autorisent ou bloquent des scripts par digest d'URL ou d'eval. Les mots-clés report-sha ne font que rapporter.

Pourquoi cela compte pour un inventaire de scripts

Une fois que le navigateur rapporte un digest pour chaque script qui se charge, un backend peut faire le travail que de simples décomptes de violations n'ont jamais pu faire : lister chaque script qui s'est exécuté, rapprocher les digests et les URL de fichiers et versions connus, et signaler un changement dès qu'un digest jamais vu apparaît.

C'est la base de l'inventaire de scripts de CentralCSP. Nous ingérons ces rapports csp-hash, construisons l'inventaire de ce qui s'exécute sur chaque page, corrélons les scripts avec les données CVE, et alertons quand un script ou un hash inattendu apparaît. Pour les pages de paiement, cette même visibilité sur les changements de scripts correspond directement aux exigences 6.4.3 et 11.6.1 de PCI DSS v4, où la plateforme vous aide à respecter les contrôles de gestion des scripts et de détection d'altération côté client (c'est votre QSA qui valide, pas nous).

Si vous voulez que les digests soient collectés et transformés en inventaire sans monter votre propre pipeline, démarrez gratuitement et pointez votre header Reporting-Endpoints vers votre endpoint CentralCSP.

Les scripts regroupés par origine, chacun avec le hash signalé par le navigateur

Récapitulatif rapide

Ajoutez un mot-clé report-sha à une directive de script, déclarez un groupe Reporting-Endpoints, et référencez-le avec report-to. Le navigateur envoie un rapport csp-hash transportant le digest de chaque script, rien n'est bloqué, et vous obtenez la visibilité par script qui alimente un inventaire de scripts. C'est du Chromium d'abord aujourd'hui, prévoyez donc une couverture partielle des navigateurs et rassemblez les digests en mode report-only avant de vous appuyer dessus.

Articles liés