Tous les articles

Comment détecter les bibliothèques JavaScript vulnérables sur un site en production

CentralCSP Team ·

Dernière mise à jour:

Votre pipeline de build exécute npm audit, votre dépôt a un scanner de dépendances, et le dernier pentest est quand même revenu avec « version vulnérable de la bibliothèque jQuery détectée ». Le scanner avait raison. La bibliothèque n'était pas dans votre arborescence source. Elle est arrivée par le widget d'un fournisseur, un conteneur de tag manager ou une URL CDN que quelqu'un a figée dans un template il y a des années, et le seul endroit où elle apparaît, c'est dans le navigateur.

Cet article explique comment détecter les bibliothèques JavaScript vulnérables qu'un site en production charge, pourquoi les outils de build en ratent une partie, et comment transformer une vérification ponctuelle en quelque chose qui vous prévient quand la prochaine CVE tombe.

Pourquoi les bibliothèques JavaScript vulnérables sont encore partout

Les bibliothèques côté client obsolètes sont l'un des constats les plus anciens de la sécurité web, et l'un des plus persistants. Une étude portant sur plus de 133 000 sites, publiée à NDSS en 2017, a montré que 37 % d'entre eux incluaient au moins une version de bibliothèque avec une vulnérabilité connue, avec un retard sur la version courante qui se mesure en années, et que beaucoup de ces inclusions venaient de services tiers et de scripts injectés dynamiquement plutôt que du code du site lui-même. Le mécanisme n'a pas changé depuis.

Trois choses maintiennent ce chiffre élevé :

  • Personne ne possède la copie tierce. Un widget de chat, un tag de test A/B ou un script publicitaire embarque sa propre copie d'une bibliothèque. Votre équipe n'a jamais choisi la version et ne la voit jamais dans un lockfile.
  • Les vieilles URL continuent de fonctionner. Une copie CDN figée dans un template en 2018 se charge aussi bien aujourd'hui. Rien ne casse, donc rien ne pousse à mettre à jour.
  • Les scanners la classent en priorité basse. Les outils de pentest classent en général une bibliothèque obsolète comme un constat informatif, donc elle reste en bas du rapport jusqu'à ce qu'une CVE exploitable en fasse un incident.

Comment les attaquants exploitent une bibliothèque vulnérable

Une bibliothèque vulnérable n'est pas une vulnérabilité en soi. C'est un raccourci vers une vulnérabilité. Le schéma classique est une fonction de bibliothèque qui fait confiance à son entrée, combinée à n'importe quel endroit de votre page où des données contrôlées par l'attaquant atteignent cette fonction.

Les avis de sécurité XSS de jQuery de 2020 sont le cas d'école. Passer du HTML d'une source non fiable à une méthode de manipulation du DOM comme .html() ou .append() pouvait exécuter du script sur les versions antérieures à 3.5.0, même après assainissement de l'entrée. Un champ de recherche qui reflète sa requête dans la page via l'une de ces méthodes suffit. Les plages de versions jQuery concernées et le correctif sont détaillés dans Quelles versions de jQuery sont vulnérables.

La pollution de prototype est l'autre classe fréquente. Un helper de fusion profonde qui copie les clés d'un JSON contrôlé par l'utilisateur sans vérifier __proto__ permet à un attaquant d'ajouter des propriétés à chaque objet de la page, et de là d'atteindre des chemins de code qui n'étaient jamais censés voir ces données. Lodash et les anciennes versions de jQuery ont toutes deux eu des avis de ce type.

Dans les deux cas, l'exploit a besoin que le code vulnérable soit chargé sur une page où une entrée non fiable y parvient. C'est pourquoi savoir quelle page embarque quelle bibliothèque compte autant que le numéro de version.

Comment vérifier aujourd'hui si un site web contient des bibliothèques JavaScript vulnérables

Pour une seule page, trois vérifications manuelles répondent à la plupart des questions :

  1. Ouvrez la console du navigateur et demandez sa version à la bibliothèque. Pour jQuery, c'est jQuery.fn.jquery. D'autres bibliothèques exposent une propriété VERSION ou version sur leur global.
  2. Ouvrez le panneau Network des DevTools, filtrez sur JS et lisez les URL des scripts. Un nom de fichier versionné ou un chemin CDN donne la version directement.
  3. Lancez le scanner en ligne de commande Retire.js sur les fichiers de script que vous avez téléchargés ou sur la sortie de votre build. Il compare le contenu et les noms des fichiers à sa base de versions vulnérables connues.
npx retire --path ./dist

Deux outils vers lesquels on se tourne encore ne fonctionnent plus comme on s'en souvient. L'audit Lighthouse qui signalait les bibliothèques front-end avec des vulnérabilités connues a été retiré dans Lighthouse 10, donc un rapport Lighthouse vert ne dit rien sur les CVE des bibliothèques. Les extensions de navigateur Retire.js ne sont plus distribuées officiellement ; l'outil en ligne de commande est la partie maintenue, et il analyse des fichiers locaux, pas une URL.

Les vérifications manuelles conviennent pour une page, un jour donné. Le problème, c'est qu'un site est fait de nombreuses pages, que l'ensemble des scripts change à chaque déploiement et à chaque publication du tag manager, et que la bibliothèque saine le lundi peut avoir une CVE le vendredi.

Ce que npm audit, Snyk et Retire.js ne peuvent pas voir

Les scanners de build lisent ce qui se trouve dans votre dépôt ou dans la sortie de votre build. Ils font ça bien. Ils ne voient pas :

  • Les scripts qu'un tag manager injecte après le build. Une publication de conteneur ajoute une bibliothèque à toutes les pages sans un seul commit.
  • Les tags tiers et les copies qu'ils embarquent. Le script du fournisseur, et tout ce qu'il charge, ne passe jamais par votre pipeline.
  • Les copies CDN référencées depuis des templates ou un CMS. Une ligne <script src="https://cdn..."> n'est une dépendance dans aucun manifeste.
  • Quelle page embarque quoi. Un scan du dépôt dit qu'une bibliothèque existe quelque part. Il ne peut pas dire si elle se charge sur la page de checkout.
  • Un fichier qui change derrière une URL stable. Un fournisseur met à jour, ou un attaquant remplace, le contenu derrière une URL que vous avez figée. Le manifeste dit toujours la même chose.

Les produits de surveillance de scripts couvrent une partie de cela en enregistrant quelles URL de script se chargent sur quelles pages, mais enregistrer une URL n'est pas la même chose que connaître la bibliothèque et la version derrière, ni savoir si un avis de sécurité la concerne. Ce qui comble l'écart, c'est une analyse de composition logicielle (SCA) exécutée sur ce que le navigateur a réellement exécuté, à l'exécution, plutôt que sur l'arborescence source.

Détecter ce que les navigateurs chargent réellement avec le hash reporting CSP

Le navigateur est le seul endroit qui voit la liste complète des scripts qu'une page exécute, et la politique de sécurité du contenu (CSP) peut lui faire rapporter cette liste. L'expression de source 'report-sha256' demande au navigateur de calculer un hash de chaque script qu'il récupère pour la page et d'envoyer un rapport csp-hash à votre endpoint. Elle rapporte, elle ne bloque jamais, donc elle est sans risque dans une politique appliquée.

Deux headers suffisent :

Reporting-Endpoints: default="https://MyEndpoint.report.centralcsp.com"
Content-Security-Policy: script-src 'self' 'report-sha256'; report-to default

Chaque rapport contient l'URL du document, l'URL du script et le hash du script, ce que la page Hashes CSP montre à l'état brut. Les mots-clés eux-mêmes sont expliqués dans les mots-clés report-sha de la CSP. Ce hash identifie le contenu exact du fichier, donc les mêmes octets servis depuis trois CDN différents se résolvent en la même version de bibliothèque, et un fichier modifié à une URL familière ressort comme un hash différent.

À partir de là, l'analyse est mécanique. Pour chaque script rapporté par les navigateurs, le moteur Technologies de CentralCSP identifie la bibliothèque, sa version, son statut de cycle de vie et les avis de sécurité publiés qui la concernent. Vous obtenez une ligne par version de bibliothèque, son statut de cycle de vie (à jour, obsolète, dormante, dépréciée), les avis qui la concernent avec leurs identifiants CVE, leur sévérité et la plage affectée, et la liste des URL de script qui l'embarquent, de sorte que vous savez si le correctif est une mise à jour de bundle, une modification de template ou un e-mail à un fournisseur.

Il n'y a aucun agent à installer et aucun crawler à planifier, parce que ce sont les navigateurs des vrais visiteurs qui font la découverte. L'inventaire se remplit au rythme où les pages sont réellement chargées, et il inclut chaque script tiers que ces pages ont tiré. Une limite à connaître : les scripts inline ne font pas partie de l'inventaire. La fonctionnalité est incluse dans les plans Scale et Enterprise ; la page des tarifs a le comparatif, et la page de la fonctionnalité supply chain présente la visite guidée.

De la détection à l'alerte

Un scan de vulnérabilités est un instantané. L'avis qui compte est celui qui sera publié le mois prochain pour une bibliothèque que vous exécutez déjà, et personne ne relance un scan le jour où une CVE tombe.

Deux règles d'alerte transforment l'inventaire en contrôle permanent :

  • New vulnerability se déclenche quand un avis est publié pour une version déjà présente sur le site, ou quand une version vulnérable est chargée pour la première fois. Une sévérité minimale garde les constats de niveau Faible hors de l'astreinte.
  • Outdated or deprecated version se déclenche quand une bibliothèque prend du retard sur sa version courante ou cesse d'être maintenue, ce qui est le signal plus précoce et plus discret qu'une CVE arrive sans correctif derrière.

Les deux règles regardent vers l'avant à partir du moment où vous les créez. Passez l'inventaire en revue une fois, puis laissez les règles le surveiller. Le guide de démarrage Technologies suit cet ordre, et les alertes arrivent sur Slack, Teams, Google Chat, Telegram, par e-mail ou via un webhook signé.

Détection à l'exécution ou scan au build ? Utilisez les deux

Les deux approches répondent à des questions différentes, et aucune ne remplace l'autre.

Scan au build (npm audit, Snyk, Retire.js)Détection à l'exécution (hash reporting CSP)
Ce qui est vuLes dépendances déclarées dans vos manifestes et les fichiers de votre sortie de buildChaque fichier de script que de vrais navigateurs ont exécuté, propriétaire et tiers
Quand ça tourneAu commit, en CI, à la demandeEn continu, au fil du chargement des pages
Angles mortsLes injections du tag manager, les tags de fournisseurs, les copies CDN, la réalité page par pageLes scripts inline, et les pages qu'aucun visiteur n'a encore chargées
Point fortBloquer une mauvaise version avant le déploiementTrouver ce qui a quand même été déployé, et attraper le prochain avis
Coût de mise en placeUne étape de CIUne expression de source CSP et un endpoint de reporting

Un constat, d'un côté comme de l'autre, a encore besoin d'une vérification d'atteignabilité avant de devenir une priorité. Un .html() vulnérable sur une page sans entrée non fiable est un ticket de backlog, pas un incident. La version et la page sur laquelle elle se charge sont ce qui vous permet de trancher vite.

FAQ

Comment savoir si mon site web utilise des bibliothèques JavaScript vulnérables ?

Ouvrez le panneau Network des DevTools, listez les fichiers JavaScript que chaque page charge, et comparez la version de chaque bibliothèque à ses avis de sécurité, ou lancez Retire.js sur les fichiers téléchargés. Pour un site entier, en continu, utilisez le hash reporting CSP pour que les navigateurs rapportent chaque script exécuté et que les versions soient confrontées aux CVE.

Lighthouse vérifie-t-il encore les bibliothèques JavaScript vulnérables ?

Non. L'audit qui signalait « Includes front-end JavaScript libraries with known security vulnerabilities » a été retiré dans Lighthouse 10, donc un rapport Lighthouse propre ne signifie pas que vos bibliothèques sont à jour. Utilisez plutôt une vérification dédiée comme Retire.js, ou une détection à l'exécution fondée sur les rapports de hash CSP.

Retire.js est-il toujours maintenu ?

Le scanner en ligne de commande Retire.js est maintenu et reste un bon moyen de vérifier les fichiers d'un dépôt ou d'un build. Ses extensions de navigateur ne sont plus distribuées officiellement. Retire.js analyse les fichiers que vous lui donnez, donc il ne voit pas les scripts qu'un tag manager ou un fournisseur ajoute à vos pages à l'exécution.

Qu'est-ce qu'un SBOM côté client ?

Une nomenclature logicielle (SBOM) côté client est la liste des bibliothèques et des versions qui s'exécutent réellement dans les navigateurs de vos visiteurs, scripts tiers et CDN compris, plutôt que la liste déclarée dans votre manifeste de paquets. Elle vient de ce que les navigateurs rapportent charger, et c'est elle que vous consultez à chaque nouvelle CVE. Technologies en est un.

Commencez par ce que voit le navigateur

Ajoutez 'report-sha256' à votre directive de script, faites pointer report-to vers un endpoint, et laissez les chargements de pages réels construire la liste. Passez ensuite en revue les lignes vulnérables une fois et créez les deux règles d'alerte pour que le prochain avis atteigne une personne. Démarrez gratuitement avec CentralCSP et l'inventaire commence à se remplir dès les premiers rapports.

Articles liés

Sources