Tous les articles

Comment protéger les scripts CDN avec Subresource Integrity

CentralCSP Team ·

Dernière mise à jour:

Quand vous chargez un script depuis un CDN, vous faites confiance à celui qui contrôle ce serveur pour ne jamais servir autre chose que le fichier attendu. Subresource Integrity (SRI) rend cette confiance inutile. Vous ajoutez un hash cryptographique du fichier attendu à la balise <script> ou <link>, et le navigateur refuse d'exécuter tout ce qui ne correspond pas.

En résumé : mettez un hash integrity sur chaque script et feuille de style tiers, et associez-le à crossorigin pour que le navigateur puisse le vérifier. Si un CDN est compromis et se met à servir du code altéré, le navigateur bloque le chargement au lieu d'exécuter le fichier trafiqué. Cet article couvre la syntaxe exacte, comment le navigateur choisit quel hash vérifier, pourquoi crossorigin est obligatoire pour les fichiers cross-origin, et comment le SRI s'articule avec votre politique de sécurité du contenu.

Qu'est-ce que Subresource Integrity ?

Le SRI est une spécification W3C qui ajoute un attribut integrity aux éléments HTML qui chargent des ressources externes. La valeur est un hash du contenu attendu. Quand le navigateur récupère la ressource, il hashe les octets reçus et les compare à votre valeur. S'ils correspondent, le fichier s'exécute. Sinon, le navigateur traite l'écart comme une erreur réseau, et la ressource n'est ni chargée, ni appliquée, ni exécutée.

Ce seul contrôle couvre un risque réel. Un compte CDN est compromis, un pipeline de build est empoisonné, ou un attaquant intercepte et remplace la réponse, et votre page se met discrètement à exécuter du code d'attaquant. Avec le SRI en place, toute modification d'un octet du fichier casse le hash et le navigateur l'écarte.

L'attribut integrity est pris en charge sur <script>, et sur <link> avec un rel de stylesheet, preload ou modulepreload.

Comment utiliser l'attribut integrity

La valeur est un ou plusieurs hashes. Chaque hash est un préfixe d'algorithme (sha256-, sha384- ou sha512-), un tiret, puis le digest encodé en base64. Plusieurs hashes sont séparés par des espaces. Le SRI impose aux navigateurs de prendre en charge SHA-256, SHA-384 et SHA-512 ; SHA-384 est un choix par défaut courant.

Voici un script cross-origin avec un hash integrity et l'attribut crossorigin dont il a besoin :

<script
  src="https://cdn.example.com/script.js"
  integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7"
  crossorigin="anonymous"></script>

Une feuille de style fonctionne de la même manière :

<link
  rel="stylesheet"
  href="https://cdn.example.com/styles.css"
  integrity="sha384-Li9vy3DqF8tnTXuiaAJuML3ky+er10rcgNR/VqsVpcw+ThHmYcwiB1pbOxEbzJr7"
  crossorigin="anonymous">

Vous générez le hash à partir du fichier exact que sert le CDN. Collez l'URL ou le fichier dans le générateur SRI, qui produit pour vous les valeurs SHA-256, SHA-384 et SHA-512. Le SRI ne se met pas à jour automatiquement : si le CDN livre légitimement une nouvelle version du fichier, vous régénérez le hash, ou la ressource cesse de se charger. C'est le comportement attendu, pas un bug. Le hash ne dit rien non plus sur la sûreté de la version épinglée, alors épinglez après la mise à jour, pas à sa place. Pour le cas de jQuery, voyez Quelles versions de jQuery sont vulnérables.

Quel hash le navigateur vérifie-t-il ?

Vous pouvez lister plus d'un hash, et c'est là que se niche une idée reçue courante. Le navigateur n'utilise pas le premier hash, et il n'utilise pas le premier algorithme qu'il prend en charge. Il utilise l'algorithme le plus fort présent.

Si votre valeur integrity contient à la fois un hash SHA-256 et un hash SHA-384, le navigateur sélectionne les hashes SHA-384 et ignore entièrement ceux en SHA-256. Lister un hash plus faible à côté d'un plus fort n'affaiblit pas le contrôle.

<script
  src="https://cdn.example.com/script.js"
  integrity="sha256-yourSha256Digest
             sha384-yourSha384Digest"
  crossorigin="anonymous"></script>

Dans cet exemple, seul le hash SHA-384 est utilisé. Ce comportement est défini dans la spécification SRI ("get the strongest metadata from set") et correspond à la façon dont les navigateurs l'implémentent : le navigateur valide avec l'algorithme le plus fort que vous listez, donc SHA-512 l'emporte sur SHA-384, qui l'emporte sur SHA-256.

Lister plusieurs hashes du même algorithme est un autre cas, et celui-là est utile. Le navigateur les garde tous, et la ressource passe le contrôle si l'un d'eux correspond. Vous pouvez ainsi accepter plusieurs versions validées d'un même fichier à la même URL.

Pourquoi crossorigin est requis

Pour une ressource cross-origin, l'attribut integrity ne fait rien à lui seul. Vous avez aussi besoin de crossorigin, et l'oublier est la première cause d'un SRI qui échoue en silence.

La raison est CORS. Sans crossorigin, le navigateur récupère un fichier cross-origin en mode no-cors, et la réponse est opaque : votre page ne peut pas lire ses octets. Les navigateurs refusent d'appliquer le SRI sur une requête no-cors, donc le chargement échoue. Autoriser le contrôle sur des réponses opaques ferait aussi fuiter des données : un attaquant pourrait deviner par force brute un contenu cross-origin en lui opposant des hashes successifs. CORS oblige donc le propriétaire de la ressource à partager explicitement le fichier avant que le SRI puisse le lire.

L'attribut crossorigin a deux valeurs utiles :

  • anonymous (ou une valeur vide) utilise CORS sans envoyer de cookies ni d'identifiants en cross-origin. Utilisez-la pour les fichiers de CDN publics.
  • use-credentials utilise CORS et envoie toujours les identifiants. Utilisez-la seulement quand le tiers l'exige.

Les ressources same-origin sont différentes. Le partage y est déjà acquis, donc un <script> same-origin avec integrity est vérifié sans crossorigin. L'attribut n'est requis qu'en cross-origin.

SRI et politique de sécurité du contenu

Le SRI vérifie le contenu d'un fichier que vous avez déjà décidé de charger. Une politique de sécurité du contenu (CSP) décide quels fichiers ont le droit de se charger tout court. Ils traitent deux moitiés du même problème et se complètent bien.

Une directive CSP script-src contrôle les origines et le code inline que votre page peut exécuter. Le SRI garantit ensuite que les fichiers tiers spécifiques que vous autorisez n'ont pas été altérés. Si vous partez de zéro, comment construire une CSP solide et la référence script-src couvrent les directives, et la page hashes et nonce CSP explique comment la CSP utilise ses propres hashes (un mécanisme distinct du SRI, pour autoriser du code inline ; voyez SRI vs hash CSP pour la distinction), et comment générer un hash CSP détaille comment en produire un.

Une directive CSP a existé pour cela, require-sri-for, censée forcer le SRI sur chaque script ou style. N'y touchez pas : elle a été retirée de la spec et n'est jamais arrivée dans les navigateurs stables. Elle n'est pas interopérable aujourd'hui. Pour exiger l'intégrité à l'échelle du site, on utilise désormais le header Integrity-Policy, qui peut bloquer les scripts dépourvus d'intégrité et les signaler comme une integrity-violation. Il est arrivé récemment dans les versions actuelles de Chrome, Firefox et Safari ; le guide appliquer le SRI partout avec Integrity-Policy le détaille. Pour la référence complète de l'attribut, du hashing et d'Integrity-Policy, voyez Subresource Integrity (SRI).

Une checklist rapide

  • Ajoutez integrity à chaque <script> et <link rel="stylesheet"> cross-origin que vous contrôlez.
  • Associez toujours un integrity cross-origin à crossorigin="anonymous".
  • Préférez SHA-384 ou SHA-512 ; si vous listez plusieurs algorithmes, le navigateur utilise le plus fort.
  • Régénérez le hash chaque fois que le fichier amont change, ou automatisez les hashes SRI dans votre build.

Le SRI durcit le code tiers que vous chargez déjà, et un inventaire de scripts vous dit en quoi consiste réellement ce code tiers. À partir des rapports de hash CSP, CentralCSP dresse l'inventaire de chaque script qui tourne sur vos pages, pour que vous voyiez les scripts nouveaux ou modifiés avant qu'ils ne deviennent un incident. Commencez gratuitement pour cartographier vos dépendances côté client.

Articles liés