Comment générer un hash Subresource Integrity (SRI)
CentralCSP Team ·
Dernière mise à jour:
Subresource Integrity (SRI) est l'attribut integrity qui demande au navigateur de comparer les octets d'un fichier externe au hash que vous fournissez, et de bloquer le fichier s'il ne correspond pas. Il vous faut donc deux choses : le hash, et le bon attribut sur la balise.
Générez le hash avec le générateur SRI : collez le fichier ou l'URL et il renvoie les valeurs SHA-256, SHA-384 et SHA-512 prêtes à coller. La valeur est le digest en base64 des octets bruts du fichier. Préfixez-la avec l'algorithme et placez-la sur la balise, avec crossorigin pour un fichier cross-origin :
<script
src="https://cdn.example.com/script.js"
integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7"
crossorigin="anonymous"></script>Vous découvrez le mécanisme lui-même ? Subresource Integrity (SRI) expliqué couvre ce que c'est et ce contre quoi il protège. Le reste de cet article donne le mode d'emploi et les pièges qui le cassent en silence.
Choisissez l'algorithme
Le SRI accepte sha256, sha384 et sha512. Préférez sha384 ou sha512. Le digest est calculé sur les octets bruts du fichier puis encodé en base64 : d'un algorithme à l'autre, seules la force et la longueur de la valeur changent.
Si vous listez plusieurs hashes dans la valeur integrity, le navigateur ne prend pas le premier. Il retient l'algorithme le plus fort présent. Avec un sha256 à côté d'un sha384, seul le hash sha384 est vérifié : lister une valeur plus faible à côté d'une plus forte n'affaiblit donc jamais le contrôle. Le générateur SRI renvoie les trois valeurs, vous pouvez donc coller celle que vous voulez.
Associez-le à crossorigin
Un <script> ou <link> cross-origin qui porte integrity mais pas crossorigin="anonymous" ne se charge jamais. C'est l'erreur SRI la plus fréquente.
Sans crossorigin, le navigateur récupère le fichier en mode no-cors et obtient une réponse opaque qu'il ne sait pas lire : il ne peut donc pas comparer les octets à votre hash, et il refuse d'exécuter le fichier. L'attribut fait passer la requête en CORS, et le navigateur peut alors lire la réponse et la vérifier.
<link
rel="stylesheet"
href="https://cdn.example.com/styles.css"
integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7"
crossorigin="anonymous">Les fichiers same-origin sont déjà lisibles, ils sont donc vérifiés sans crossorigin. L'attribut n'est exigé qu'en cross-origin.
Vérifiez que ça marche
Chargez la page et surveillez le fichier. Un hash correct se charge sans bruit. Un hash faux, ou un crossorigin manquant sur un fichier cross-origin, fait échouer le chargement et inscrit une erreur d'intégrité dans la console du navigateur.
Pour vérifier qu'une non-correspondance est bien détectée, changez un caractère dans la valeur integrity et rechargez : le script doit être bloqué et la console doit signaler que la ressource n'a pas passé son contrôle d'intégrité. Remettez la valeur correcte une fois le blocage constaté.
Gardez les hashes à jour quand les fichiers changent
Le SRI ne se met pas à jour tout seul. Le hash est lié aux octets exacts du fichier, il faut donc le régénérer chaque fois que le contenu du fichier change. C'est le comportement attendu : un fichier modifié avec un ancien hash est traité comme une falsification et bloqué.
C'est pourquoi une URL de CDN « latest » ou auto-minifiante casse le SRI : les octets peuvent changer sous vos pieds sans prévenir, et le prochain déploiement de leur côté bloque votre page. Épinglez une URL immuable et versionnée (un chemin de version précis, pas une étiquette mouvante) pour que le fichier que vous avez hashé reste celui que vous recevez.
C'est aussi cette charge de maintenance qui pousse les équipes à suivre les scripts tiers qu'elles déploient. À partir des rapports de hash CSP, CentralCSP construit un inventaire de scripts de tout ce qui tourne sur vos pages, pour que le changement d'un fichier tiers vous saute aux yeux au lieu de vous arriver par un chargement bloqué.
Faites-le avec les outils de build
Générer les hashes à la main devient vite ingérable au-delà de quelques fichiers. La plupart des bundlers savent émettre les attributs integrity automatiquement pendant le build, vous pouvez donc l'automatiser avec Webpack ou Vite :
- Webpack : webpack-subresource-integrity ajoute l'attribut
integrityaux balises<script>et<link>émises. - Vite : un plugin communautaire tel que @small-tech/vite-plugin-sri calcule et injecte les hashes au moment du build.
Ils gardent le hash synchronisé avec le fichier, ce qui vous épargne la régénération à chaque changement sur vos propres assets bundlés.
Ce n'est pas la même chose qu'un hash CSP
Un hash SRI et un hash CSP se ressemblent, et on les confond facilement. Ils ne hashent pourtant pas la même chose.
- Le SRI hashe un fichier externe et va dans l'attribut
integritysur la balise. - Une source CSP
'sha256-...'hashe le contenu d'un script inline et va dans la directivescript-srcde votre politique de sécurité du contenu.
Si vous autorisez un bloc <script> inline, c'est le hash CSP qu'il vous faut, pas le SRI. Comment générer un hash CSP (sha256) couvre ce cas.
Où l'exiger
L'attribut integrity s'ajoute balise par balise. Pour exiger le SRI sur tout un document d'un coup, il existe le header Integrity-Policy, qui demande au navigateur de refuser toute sous-ressource du périmètre chargée sans métadonnées d'intégrité.
Integrity-Policy: blocked-destinations=(script)Integrity-Policy est disponible depuis peu dans les versions actuelles de Chrome, Firefox et Safari. La référence Integrity-Policy détaille les directives et le rapport qu'elle émet.
Prochaines étapes
Ajoutez integrity et crossorigin à vos scripts et feuilles de style cross-origin, épinglez leurs URL, et configurez votre bundler pour qu'il émette les hashes de vos propres assets. Si c'est un scanner qui vous amène ici, voyez si un scanner a signalé votre SRI. Pour savoir quel code tiers vous chargez vraiment avant de commencer à le hasher, commencez gratuitement et laissez CentralCSP inventorier vos scripts côté client.