Verrouillez vos dépendances pour empêcher les attaques sur supply chain
Si vous avez suivi l’actualité récente, une nouvelle attaque de type supply-chain a affecté des versions récentes de plusieurs packages TanStack.
Cet article propose une approche simple pour réduire la probabilité et l’impact de ce type de faille de sécurité dans vos applications.
Sommaire
- Qu’est-ce qu’une attaque de type supply chain ?
- Que s’est-il passé ?
- Pourquoi d’autres projets ont-ils été affectés ?
- Comment le verrouillage des versions réduit les risques
- Limites de cette solution
- Conclusion
Qu’est-ce qu’une attaque de type supply chain ?
Un package logiciel dépend de plusieurs éléments tout au long de son cycle de vie :
Développeur -> Ordinateur -> Dépôt GitHub -> Registre de packages (NPM)
Une attaque de type supply chain se produit lorsqu’un de ces éléments est compromis, permettant à du code malveillant de se propager à travers le reste de la chaîne.
En pratique, cela signifie souvent qu’un attaquant parvient à injecter du code malveillant dans un package dont dépendent de nombreux autres projets.
Que s’est-il passé ?
Un attaquant a soumis une pull request malveillante ciblant l’un des packages TanStack.
La pull request contenait du code JavaScript malveillant dissimulé. Lorsque la CI s'est executée, un workflow GitHub Action s’est exécuté et l’attaque a empoisonné le cache GitHub Actions.
Le cache ayant été infecté, le code malveillant a ensuite pu capturer des identifiants sensibles, y compris des tokens GitHub.
Grâce à ces identifiants, l’attaquant a obtenu des permissions élevées et a publié des versions compromises des packages sur NPM.
Résultat : les développeurs installant les versions affectées ont téléchargé du code malveillant dans leurs projets sans le savoir.
Pourquoi d’autres projets ont-ils été affectés
Par défaut, les projets Node.js autorisent généralement les mises à jour de dépendances au sein de la même version majeure.
Par exemple :
npm install solid-js
Cela produit l’entrée suivante dans package.json :
{
"dependencies": {
"solid-js": "^1.9.5"
}
}
Le caractère ^ signifie :
Autoriser automatiquement les futures mises à jour mineures et correctives.
Ainsi, même si votre projet utilisait initialement 1.9.5, une réinstallation ultérieure des dépendances peut installer une version plus récente comme 1.11.2.
Cela peut se produire dans de nombreuses situations :
- Un nouveau développeur rejoint l’équipe et installe les dépendances
- Un pipeline CI/CD exécute
npm install - Une GitHub Action lance des tests automatisés
- Vous réinstallez les dépendances après avoir supprimé
node_modules - Vous exécutez
npm update
Si une version malveillante est publiée pendant cette fenêtre de temps, votre projet peut la récupérer automatiquement.
Comment le verrouillage des versions réduit les risques
L’objectif est simple :
Si la version
X.Y.Zfonctionnait hier, installer exactement cette même version demain.
NPM fournit un flag --save-exact pour cela :
npm install --save-exact solid-js
Cela génère ce résultat dans votre fichier package.json :
{
"dependencies": {
"solid-js": "1.9.5"
}
}
Remarquez que le ^ a disparu.
Désormais, chaque npm install utilisera exactement la même version sauf si vous la modifiez explicitement vous-même.
Vous pouvez également verrouiller manuellement une version spécifique :
npm install --save-exact solid-js@1.8.0
Cette approche existe dans de nombreux écosystèmes.
PHP
composer require laravel/reverb:1.10.1
Ruby
gem install sidekiq -v 8.1.4
Python
poetry add requests@2.34.0
Limites de cette solution
Comme toujours en programmation, il n’existe pas de solution miracle.
Cette approche implique plusieurs compromis :
- Vous devez vérifier et mettre à jour les dépendances manuellement
- Vous devriez exécuter
npm outdatedrégulièrement afin de rester à jour sur les correctifs de sécurité - Le verrouillage des dépendances directes ne protège pas totalement contre des dépendances transitives compromises
- Les vulnérabilités de sécurité peuvent rester inaperçues plus longtemps si les mises à jour sont retardées
Autrement dit, le verrouillage des versions réduit la surface d’attaque, mais n’élimine pas complètement les risques de type supply chain.
Conclusion
Les attaques de type supply chain nécessitent une surveillance active et de bonnes pratiques de sécurité.
Le verrouillage exact des versions n’est pas une solution miracle, mais il aide à réduire l’imprévisibilité et limite le risque d’installer accidentellement de nouvelles versions compromises de packages.
Un avantage supplémentaire est la reproductibilité des builds :
- les membres de l’équipe utilisent les mêmes versions de dépendances
- les environnements CI deviennent plus prévisibles
- le débogage devient plus simple
- les régressions inattendues liées aux dépendances sont réduites
Cependant, cette approche augmente également la charge de maintenance car les mises à jour de dépendances doivent être examinées plus attentivement.
Pour certaines équipes, ce compromis en vaut la peine. Pour d’autres, cela peut sembler trop restrictif.
L’important est de comprendre les risques et de prendre une décision intentionnelle plutôt que de s’appuyer sur le comportement par défaut du gestionnaire de packages.