Dans le développement de logiciels, nous dépendons à la fois de composants ou d’artefacts propres et tiers. Une gestion flexible des dépendances est essentielle pour les logiciels modernes. Les gestionnaires de packages comme NPM, Maven, pépin or NuGet sont souvent utilisés pour spécifier les dépendances logicielles. Ces outils ont été conçus dans un souci de commodité et de facilité d’utilisation, et non de sécurité.
Le problème
Le problème est que la flexibilité et la facilité d'utilisation sont considérées par les développeurs comme des méchants, qui considèrent les dépendances logicielles comme un charme irrésistible pour leur entreprise. Résultat : les mauvais acteurs ont suivi toutes les voies d'attaque possibles indiquées ici. Source : « Backstabber's Knife Collection : Un examen des attaques de la chaîne d'approvisionnement de logiciels open source »
Dans cet article, nous nous concentrerons sur l'utilisation des déclarations de version ouverte, dans le sens où la version téléchargée n'est pas fixe mais doit appartenir à une certaine plage. Au moment de la construction, la version existante la plus élevée compatible avec la plage de versions spécifiée est choisie et téléchargée/installée par le gestionnaire de packages.
Illustrons les déclarations ouvertes dans les déclarations de dépendances pour différents gestionnaires de packages :
-
- NMP : package.json
{
...
"dépendances": {
...
« accepte » : « >=1.3.8 »,
"lodash": "~4.16.0",
...
},
...
}
La plus grande version existante non inférieure à 1.3.8 pour le package accepte sera installée, ainsi que la plus grande mise à jour de « correctif » pour lodash dans la gamme 4.16.x.
-
- Maven : pom.xml
...
...
commons-io
commons-io
LIBÉRATION
...
...
La dernière version disponible pour commons-io (fichier jar) sera ajoutée en tant que dépendance.
-
- Pépin: configuration.py
...
installation(
...
install_requires=['poivre', 'launchpadlib'],
...
)
...
De tels systèmes de versions ouvertes ont des bons et des mauvais côtés. Le bon côté c'est que les versions les plus récentes d'habitude contiennent des améliorations fonctionnelles et de qualité, des corrections de bugs et des correctifs de sécurité, qui sont automatiquement mis à niveau. Veuillez noter que pour la plupart des projets réels, les correctifs ne sont pas rétroportés vers les versions mineures précédentes, sauf peut-être pour des vulnérabilités de sécurité catastrophiques. Les versions ouvertes peuvent également être utilisées dans les bibliothèques, afin de réduire le nombre de versions à installer lorsque toutes les dépendances sont résolues.
Mais les gammes de versions ouvertes ont un mauvais côté. Vous ne savez pas exactement quelles versions seront installées au moment de la construction, et les versions ne sont pas reproductibles. Et il y a aussi un entrepôts côté avec les versions ouvertes. Si un acteur malveillant parvient à publier un composant malveillant dans le référentiel public avec une version élevée compatible avec votre gamme ouverte, votre prochaine version inclura le composant malveillant, peut-être même en exécutant un logiciel malveillant dans des scripts d'installation qui pourraient être exécutés automatiquement. Dissimuler la charge utile de l’attaque relève de tout un art.
Ceci est connu comme le Absence d'épinglage de version problème.
Les acteurs malveillants tentent toujours d'introduire des versions malveillantes de packages open source populaires. Ils peuvent accéder aux clés des référentiels de packages dans une fuite secrète ; ils utilisent souvent l'ingénierie sociale ou cachent une dépendance malveillante imbriquée dans un package apparemment utile. pull request. Même quelques auteurs eux-mêmes décident un jour que le monde n'est pas juste et mordent leurs clients avec logiciel de protestation dans leurs propres emballages !
Imaginez maintenant que vous travaillez pour une organisation qui utilise des composants internes ainsi que des composants open source.
Si un acteur malveillant connaît le nom de ces composants internes, il peut parvenir à publier un composant du même nom dans le référentiel public. De nombreux gestionnaires de packages obtiennent d'abord les composants publics, et si la version est correctement choisie et que la version dans votre dépendance déclarée est ouverte, boum ! Ce problème est nommé Confusion des dépendances.
Montrons un exemple. Supposons que dans notre projet NPM nous ayons une dépendance à un composant privé :
-
- NMP : package.json
{
"name": "mon-projet",
...
"dépendances": {...
"mon-dépôt-privé": ">=1.0.0",...
}
...
}
L'attaquant peut créer une version majeure de my-private-dep (comme 99.0.0) et la publier dans le référentiel public npm, avec son propre faux compte (l'attaquant n'a rien à faire avec mon organisation). Le gestionnaire de packages NPM installera la dépendance malveillante, souvent avec des résultats dévastateurs.
La solution
Pour éviter ces problèmes dans notre processus de création de logiciels, nous devons suivre des normes strictes sur la façon de déclarer les versions des composants, qui dépendent de la technologie utilisée. L'important est qu'une version spécifique d'un package, une fois publiée dans un référentiel, soit immuable (pour éviter de casser les dépendances, et pas seulement pour des raisons de sécurité).
L'idée générale est de fixer (épingle), en vérifiant toujours que les versions corrigées des composants (y compris TOUTES les dépendances transitives) sont exemptes de malware, et cela est possible grâce au fichiers de verrouillage que proposent de nombreux gestionnaires de packages. Voyons comment fonctionne l'épinglage de version pour différents gestionnaires de packages. Il existe un compromis délicat entre mises à jour fréquentes des versions pour corriger les vulnérabilités connues et épinglage de version pour éviter les constructions non déterministes et les attaques potentielles de la chaîne d’approvisionnement.
-
- NPM:
Les gestionnaires de packages npm ou Yarn utilisent différents fichiers de verrouillage (npm-shrinkwrap.json / package-lock.json ou Yarn.lock, respectivement) qui répertorient les versions corrigées pour toutes les dépendances, directes et indirectes. Les fichiers de verrouillage doivent être sous contrôle de version, sinon d'autres développeurs/nœuds de build peuvent se retrouver avec des versions différentes. Évitez l'installation de npm sauf si, en cours de développement, vous devez mettre à jour les dépendances (par exemple pour installer des correctifs de sécurité). Utilisez le npm ci (Clean Install) plus déterministe en général, de sorte que le gestionnaire de packages utilisera le fichier de verrouillage ou se terminera avec une erreur s'il n'y a pas de fichier de verrouillage ou s'il ne correspond pas au package.json. Si les versions répertoriées ont été vérifiées pour détecter les logiciels malveillants, le fichier de verrouillage garantit que rien de grave ne se produira au moment de la construction.Pour les composants internes, il est recommandé de créer un Portée du NMP géré par l'organisation (comme @myorg) et utilisez cette portée dans la dépendance (comme @myorg/my-private-dep), qui ne peut avoir qu'une visibilité privée. Cela bloque dépendance confusion attaques, car seuls les membres de l’organisation disposant d’un accès en écriture peuvent publier des packages dans une telle portée.
- NPM:
-
- Maven:
Maven / Gradle n'ont pas de fichiers de verrouillage (mais voir cet article StackOverflow).Les plages de versions ne sont pas autant utilisées avec Maven/Gradle qu'avec d'autres écosystèmes. Il suffit d'éviter gammes de versions et les méta-versions DERNIÈRES ou RELEASE. Les versions indirectes doivent également être vérifiées. Le Versions du plugin Maven est un bon outil pour le contrôle de version.
Veuillez noter que Maven a toujours eu le concept de portée de l'organisation (la partie groupId de la dépendance), et la confusion des dépendances ne semble pas du tout être un problème pour cet écosystème.
- Maven:
-
- Pépin:
En Python, il existe différents outils pour gérer les fichiers de verrouillage :- pipenv, qui génère un fichier de verrouillage Pipfile.lock.
- poésie, qui génère poésie.lock.
- gel de pépin, commande qui génère un fichierRequirements.txt qui fait office de fichier de verrouillage. Vérifiez si toutes les dépendances utilisent des versions corrigées avec l'opérateur ==. Ensuite, pip install -r Requirements.txt utilise les dépendances fixes.
- Pépin:
Rappelez-vous que les fichiers de verrouillage ci-dessus doivent être sous contrôle de version et que la commande de build choisie doit utiliser le fichier de verrouillage.
Le référentiel de packages habituel utilisé avec pip (PyPI) n'a pas de portée de nom et il est vulnérable aux attaques de confusion de dépendances. Éviter la confusion des dépendances dans l'écosystème Python n'est pas facile, et certains auteurs recommandent d'utiliser un référentiel interne pour agir comme un proxy pour les dépendances publiques récupérées depuis PyPI, mais en prenant d'abord les dépendances privées du référentiel interne (-index-url doit pointer vers le référentiel interne, pas vers PyPI, et –extra-index-url doit être supprimé).
Quelques véritables attaques
Attaque GetCookies: L'acteur Dustin87 a ajouté une dépendance indirecte dans le package populaire npm mailparser à un package malveillant avec une porte dérobée RCE (gCOMMANDhDATAi) :
JSON.stringify(req.headers).replace(/g([a-f0-9]{4})h((?:[a-f0-9]{2})+)i/gi, (o, p, v) => {})
Malgré son désapprobation (aucun réviseur !), Mailparser a tout de même enregistré environ 64,000 XNUMX téléchargements hebdomadaires. Il s'agit d'une attaque évitée de justesse, car l'exécution de code à distance n'a pas été réellement exécutée.cised.
Publication du MNP cet article avec des détails sur l'attaque getcookies.
Confusion des dépendances:
Alex Birsan a découvert en 2021 le problème de confusion des dépendances et a publié un article intitulé «Comment j'ai piraté Apple, Microsoft et des dizaines d'autres sociétés ».
N'oubliez pas que pour npm, la portée de l'organisation comme @myorg doit être réservée et que les packages internes doivent être modifiés pour utiliser la portée.
Avec pip, le registre public commun PyPI n'a pas de portées/espaces de noms. Chaque package privé peut avoir un package public squat portant le même nom que le package interne, mais vide, et générant peut-être une erreur lors de son utilisation, afin qu'il puisse être identifié s'il est accidentellement récupéré.
Nœud-IPC:
Le propriétaire du package, lorsque la guerre entre la Russie et l'Ukraine a commencé, a injecté un code malveillant pour supprimer des fichiers aléatoires lorsqu'ils étaient installés sur des hôtes russes et biélorusses. Le fichier ssl-geospec.js faisait une telle distinction géographique :
Chose intéressante, d'autres packages utilisaient des versions ouvertes pour la dépendance node-ipc, comme le framework populaire Vue.js, et ses responsables ont reçu un appel urgent pour épingler la dépendance node-ipc sur une version sécurisée.
Ce le message contient plus de détails sur ce sabotage, qui va un peu plus loin que les autres Logiciel de protestation problèmes.
Remarques finales
Les versions ouvertes devraient jamais être utilisé dans des projets logiciels consolidés. Ils rendent les builds non reproductibles et les attaquants peuvent les exploiter et parvenir à injecter des logiciels malveillants via des attaques contre les arbres de dépendances, comme la confusion des dépendances susmentionnée.
Des configurations incorrectes comme versions ouvertes, manque d'épinglage de version ou composants internes non délimités devrait être évité. La première chose est de détecter de tels problèmes, peut-être même de bloquer la construction lorsqu'ils sont détectés, et d'avoir standardisé un protocole d'action.
Détection automatique des failles et des mauvaises configurations dans les dépendances, signalant les dépendances suspectes qui pourraient être vulnérables à des attaques spécifiques de la chaîne d'approvisionnement comme dépendance confusion, le tout doté d'outils de réparation exploitables, est l'un des principaux objectifs du Plateforme Xygeni.
| Pour en savoir plus |
| Ohm M., Plate H., Sykosch A., Meier M. : « Backstabber's Knife Collection : A Review of Open Source Software Supply Chain Attacks ». DIMVA 2020. Lecture Notes in Computer Science, vol 12223. Springer – 2020 (source de la figure de l'arbre d'attaque de dépendance.) |
| @adam-npm : « Module malveillant signalé : getcookies« . Blog npm (archivé) – 2 mai 2018. |
| Alex Birsan : «Comment j'ai piraté Apple, Microsoft et des dizaines d'autres sociétés». Moyen – 9 février 2021. |
| Hache Sharma : «GROS sabotage : le célèbre package npm supprime des fichiers pour protester contre la guerre en Ukraine» BleepingComputer – 17 mars 2022 |





