Aller au contenu

CICD-SEC-3 : abus de la chaîne de dépendances

Troisième entrée du Top 10 OWASP CI/CD. Libellé officiel : Dependency Chain Abuse. Le risque porte non sur les vulnérabilités connues des bibliothèques employées, sujet largement outillé, mais sur la façon dont les dépendances sont récupérées. Une configuration inadéquate conduit un développeur, ou l’environnement de construction, à télécharger un paquet hostile à la place de celui qu’il demandait.

→ Lire l’explication complète de la marmotte

Le mécanisme : quatre façons de se faire servir autre chose

Section intitulée « Le mécanisme : quatre façons de se faire servir autre chose »

Beaucoup d’organisations se donnent du mal pour détecter les paquets porteurs de vulnérabilités connues. Le référentiel pose à côté de cet effort une famille de contrôles aussi nécessaire et presque toujours absente : celle qui sécurise le processus de récupération. Quatre vecteurs.

La confusion de dépendances. Publier dans un dépôt public un paquet portant le nom d’un paquet interne, pour que le client, interrogeant les deux sources, choisisse le public. Le mécanisme est arithmétique : entre deux versions du même nom, le client prend la plus élevée, et l’attaquant publie un numéro absurde. Le travail d’Alex Birsan qui a nommé ce vecteur a touché des dizaines de très grandes entreprises, et des applications Node.js d’Amazon, Zillow, Lyft et Slack ont ensuite été visées par le même défaut.

Le détournement de compte de mainteneur. Prendre le contrôle du compte d’un mainteneur, puis publier une nouvelle version d’un paquet très employé. Trois bibliothèques npm en portent le souvenir : ua-parser-js et coa, neuf millions de téléchargements hebdomadaires chacune, et rc, quatorze millions, détournées pour voler des identifiants ou lancer des mineurs. Ce vecteur est la projection de CICD-SEC-2 sur l’écosystème public : le compte d’un bénévole protège une dépendance de production.

Le typosquattage et l’usurpation de marque. Des paquets aux noms voisins de paquets populaires, en comptant sur la faute de frappe ; ou des paquets qui respectent la convention de nommage d’une marque connue, pour que le développeur les associe à tort à un fournisseur de confiance, variante plus coûteuse à monter et plus difficile à repérer. Le typosquattage a désormais une forme qui se passe de la faute de frappe : l’hallucination de paquets et le slopsquatting, où l’assistant invente le nom et l’attaquant l’enregistre.

La gravité de l’entrée tient toutefois à un point explicite du référentiel : souvent le paquet n’est pas seulement téléchargé, il est exécuté immédiatement après, par les scripts de pré-installation conçus exprès pour faire tourner du code à la récupération. Il n’y a donc pas de fenêtre entre « le mauvais paquet est arrivé » et « il s’exécute », et aucune revue ne s’y glisse. Au sens du catalogue CWE, c’est de l’injection de code par un chemin que personne ne regarde comme une entrée.

L’exécution de code sur l’hôte qui récupère le paquet : le poste d’un développeur, ou le nœud de construction. De là, les deux mouvements habituels, vol d’identifiants et déplacement latéral dans l’environnement où le code tourne, celui-là même que décrit CICD-SEC-5. Le poste de développement est traité sur le site comme la cible oubliée qu’il est, et dans la sécurité des postes de développeurs.

Le second scénario est le passage en production. Le référentiel note le détail qui allonge l’exposition : le paquet malveillant continue souvent d’assurer la fonctionnalité attendue, ce qui réduit la probabilité de découverte. Rien ne casse, donc personne ne cherche, ressort décrit dans les attaques sur la chaîne d’approvisionnement et l’éditorial du même nom.

Le trafic qui contourne le proxy interne. La détection la plus rentable, et de nature réseau : tout client qui joint directement un dépôt public est hors politique, quel que soit le paquet récupéré. Sans ce point de passage unique, il n’y a d’ailleurs aucune capacité d’enquête : personne ne sait ce qui a été téléchargé.

L’écart entre le verrou et ce qui est installé. Un paquet absent du verrouillage, ou dans une autre version, est un signal net : les dépendances transitives disent pourquoi l’écart est fréquent, les builds reproductibles pourquoi le supprimer est difficile.

Les noms proches des projets internes, publiés en public. Une veille sur les dépôts publics repère la confusion de dépendances et le typosquattage avant l’installation. Ce n’est pas de la supervision, et cela se délègue bien.

L’inventaire de ce qui tourne, enfin, condition de toutes les autres : la nomenclature logicielle et sa génération dans la chaîne d’intégration. Le jour où un paquet est déclaré compromis, « l’avions-nous » se répond en minutes ou en semaines selon qu’on tient cet inventaire.

Le référentiel reconnaît d’emblée que la prévention complète n’est pas accessible, vu le nombre de gestionnaires de paquets en usage simultané, et recommande d’investir aussi dans la détection et la limitation des dégâts. Les principes directeurs, eux, sont partout les mêmes.

Aucun client ne récupère de paquet directement depuis Internet. Soit tout passe par un proxy interne, qui ajoute des contrôles et garde une trace, soit les clients ne pointent que vers des dépôts internes de paquets pré-validés ; et cette configuration doit être vérifiée par un mécanisme, puisqu’une configuration de client est un fichier modifiable. Vérifier condensats et signatures, seule mesure qui distingue un paquet d’un autre indépendamment de son nom.

Ne jamais demander la dernière version, mais une version pré-validée, et un verrou maintenu vers une version stable : la confiance accordée aux mises à jour automatiques en dit aussi le coût.

Employer les espaces de nommage. Enregistrer les paquets privés sous l’espace de l’organisation, les référencer par cet espace, et forcer les clients à ne le récupérer que depuis le dépôt interne : trois réglages qui ferment la confusion de dépendances par construction, là où la veille ne fait que l’observer.

Isoler les scripts d’installation, dans un contexte distinct, sans accès aux secrets ni aux ressources sensibles des autres étapes. C’est la recommandation la plus directement protectrice de l’entrée.

Mettre la configuration du gestionnaire de paquets dans le dépôt du projet, pour écraser une configuration locale douteuse, et ne pas publier les noms des projets internes, matière première de la confusion de dépendances.

La même discipline vaut pour les conteneurs, avec la généalogie des images de base, et quand la dépendance est un fournisseur, avec la gestion des risques tiers. Le Top 10 OWASP de l’open source traite la même matière sous l’angle du choix du composant, non de son transport.

  • CICD-SEC-3: Dependency Chain Abuse, OWASP Top 10 CI/CD Security Risks, 2022 : définition, quatre vecteurs, recommandations.
  • Références citées par le document : le travail d’Alex Birsan sur la confusion de dépendances, les paquets npm visant des applications Node.js d’Amazon, Zillow, Lyft et Slack, et les détournements de ua-parser-js, coa et rc.

Sans point de passage unique, la question « avons-nous téléchargé ce paquet, quand, et sur quelles machines » reste sans réponse : chaque poste et chaque nœud a joint le dépôt public par lui-même, et aucun registre n’existe. L’organisation apprend par la presse qu’une bibliothèque qu’elle emploie peut-être a été détournée, et passe la journée à chercher si elle l’emploie. Sans espaces de nommage réservés, le scénario se rejoue à chaque projet interne dont le nom est devenu public par une offre d’emploi. Et sans isolation des scripts d’installation, le paquet hostile s’exécute dans le contexte le plus riche de la chaîne, celui qui détient les secrets de déploiement, tandis que le journal montre une construction réussie.

Un logiciel moderne n’est presque jamais écrit en entier par l’équipe qui le livre : il assemble des centaines de briques publiques, récupérées sur Internet par un outil propre au langage. C’est ce qui rend le développement rapide, et c’est la porte décrite ici.

Le défaut ne porte pas sur la qualité des briques mais sur la façon de les demander. Quatre tromperies sont recensées. La première publie, dans l’entrepôt public, une brique portant le nom exact d’une brique interne à l’entreprise : l’outil interroge les deux entrepôts et retient la version la plus récente, que l’attaquant numérote exprès très haut. La deuxième prend le contrôle du compte de la personne qui entretient une brique très utilisée, souvent bénévole, et publie une version piégée : trois bibliothèques du monde JavaScript, employées des millions de fois par semaine, en ont fait l’expérience. Les deux dernières jouent sur le nom, par la faute de frappe ou par l’imitation d’une marque connue.

Un détail décide de la gravité : dans beaucoup de langages, installer une brique ne consiste pas seulement à la copier, mais à exécuter un petit programme fourni avec elle. Le code de l’attaquant tourne donc au moment de l’installation, sur le poste du développeur ou sur la machine qui assemble le logiciel, sans qu’aucune relecture ait pu se glisser entre les deux. Et comme la brique piégée continue en général de faire son travail, rien ne casse, donc personne ne cherche.

Les mesures efficaces sont peu nombreuses et peu glorieuses : faire passer toutes les récupérations par un entrepôt interne, qui sert de filtre et de registre ; vérifier empreintes et signatures, qui identifient une brique indépendamment de son nom ; ne jamais demander « la dernière version » mais une version choisie ; réserver dans l’entrepôt public l’espace de nommage de l’entreprise ; et faire tourner les programmes d’installation dans un coin isolé, sans accès aux mots de passe.

À lire aussi

  • CICD-SEC-4 : exécution de pipeline empoisonnéeCICD-SEC-4 du Top 10 OWASP CI/CD : l'exécution de pipeline empoisonnée, ses trois formes directe, indirecte et publique, ce que l'identité du pipeline apporte à l'attaquant, et pourquoi la revue de code n'est pas sur ce chemin.
  • CICD-SEC-5 : contrôles d'accès du pipeline insuffisantsCICD-SEC-5 du Top 10 OWASP CI/CD : le PBAC, contexte d'exécution de chaque pipeline et de chaque étape. Ce que le nœud atteint, ce qu'une exécution hostile en tire, et la granularité qui décide des dégâts.
  • CICD-SEC-7 : configuration système non sécuriséeCICD-SEC-7 du Top 10 OWASP CI/CD : les défauts de durcissement des systèmes de la chaîne, l'accès réseau, les identifiants par défaut, et le piège du mode de mise au point sur un nœud de construction.
  • CICD-SEC-10 : journalisation et visibilité insuffisantesCICD-SEC-10 du Top 10 OWASP CI/CD : pourquoi les environnements d'ingénierie échappent aux programmes de journalisation, la distinction entre journaux d'audit et journaux applicatifs, et l'accès programmatique comme angle mort.

Pages voisines

: les deux pages se citent l’une l’autre.