Home >> Blog >> Supply Chain Attack, Mettre à jour régulièrement ses dépendances

Supply Chain Attack, Mettre à jour régulièrement ses dépendances

10 octobre 2023

By Yann Albou.

Après avoir expliqué les principes des attaques de la chaîne d’approvisionnement (Supply Chain Attack) puis de comment lister ses dépendances pour tracker les vulnérabilités au travers de la SBOM, nous allons nous attarder sur la mise à jour des dépendances.

Broken Chain

Cet article s’inscrit dans une série : "Comment se protéger d’une "Supply Chain Attack"" ?

  • La Supply Chain Attack ?
  • Publier sa SBOM
  • Mettre à jour régulièrement ses dépendances !
  • Assurer l’immutabilité des containers
  • Réduire la surface d’attaque des containers
  • Eliminer les secrets dans les containers & repos
  • Système de scanning régulier
  • S’assurer de l’intégrité des composants
  • Isoler les registries & promouvoir les images
  • Mettre en place GitOps
  • Politique d’admission Kubernetes
  • Mettre en place une RBAC forte
  • Solution d’observabilité des risques
  • Fortifier la Software Factory
  • Conclusion et évolutions de la Supply Chain

Mettre à jour ses dépendances, packages et images est une tâche nécessaire, mais dans quel but ? qui doit s’en préoccupper et surtout comment s’y prendre ?

Comme expliqué dans l’article La Supply Chain Attack ? et afin de faciliter la mise en application de nos recommandations, nous avons adopté une signalétique. Voici celle concernant notre sujet:

Broken Chain

Le champ d’application concerne la partie Dev et CI (Continuous Integration). C’est une pratique à mettre en place qui demande un effort modéré. Cette recommandation offre une mitigation du risque de type probabilité permettant de réduire sa possibilité de se réaliser.

Pourquoi maintenir ses applications à jour ?

Lors de la conception d’une nouvelle application ou d’une nouvelle image Docker, les actions de choix des versions des bibliothèques, des dépendances, des packages et des images de base sont souvent effectuées assez tôt dans le cycle de vie du projet et sont ensuite rarement remises en question sauf lors des moments clés de ces projets.

Pourquoi envisager des mises à jour si le projet fonctionne déjà sans problème avec les versions actuelles ? En réalité, il y a plusieurs raisons importantes de le faire :

  • Pour résoudre les bugs existants.
  • Pour remédier aux vulnérabilités éventuelles.
  • Pour intégrer de nouvelles fonctionnalités.
  • Pour profiter des améliorations de performance potentielle résultant des optimisations apportées au code.

En termes de sécurité, le Top 10 OWASP (Open Worldwide Application Security Project) fournit plusieurs classements des 10 risques et vulnérabilités les plus critiques dans différents domaines. On y retrouve, par exemple, les composants vulnérables et obsolètes : A06 – Vulnerable and Outdated Components ou les problèmes de dépendances dans la CI/CD: CICD-SEC-3: Dependency Chain Abuse.
Ces catégories de l’OWASP mettent en évidence le fait que de nombreuses applications utilisent des composants tiers pour accélérer le développement, mais ne les mettent pas à jour régulièrement ou ne surveillent pas les vulnérabilités connues dans ces composants.

Le Top 10 OWASP rappelle donc l’importance de la gestion des composants logiciels dans le contexte de la sécurité des applications.

A quel rythme faut-il être à jour ?

Rester constamment à jour peut être un défi mais toutes ces améliorations contribuent à garantir la maintenabilité du code et la robustesse de votre application.
Le faire très régulièrement vous évite les gros changements de type big-bang au profit de mises à jour plus ciblées.

De plus, en cas de vulnérabilités critiques ou de correctifs de sécurité importants, vous devriez mettre à jour immédiatement les dépendances. La sécurité de votre application doit toujours être une priorité.

Garder son système et ses dépendances à jour est donc primordial pour la sécurité et la maintenabilité de ses applications.

La mise à jour des dépendances : une action pas si simple !

Maintenir à jour les outils et packages d’un projet peut être difficile. Cela peut causer des problèmes (breaking changes) dans le fonctionnement de l’application.
De plus, cela demande du temps et des tests pour s’assurer que tout fonctionne correctement.

De nombreuses équipes choisissent de ne mettre à jour que lorsque cela est vraiment nécessaire, ce qui est une optimisation locale à un instant t, mais qui entraînera des problèmes plus importants dans le futur, voire des impacts très néfastes sur la maintenance et la sécurité des applications.

Pourtant, il est important de garder les choses à jour car cela améliore la sécurité, rend les développeurs plus à l’aise et permet de rester au courant des nouveautés. Les mises à jour régulières sont plus faciles à gérer que de gros changements après de longues périodes sans mise à jour.

C’est l’éternelle question de la dette technique: quand faut-il faire cet effort ?
Comme expliqué dans l’article sur la Supply Chain Attack ? les vecteurs d’attaques se multiplient, et ce n’est plus une option que de se mettre à jour très régulièrement !
Il devient donc important d’augmenter sa capacité à déployer mais attention à ne pas saturer cette capacité de changement pour uniquement de la mise à jour de dépendances.

Qui s’occupe de faire ces actions de mise à jour ?

La responsabilité de faire ces actions de mise à jour peut varier en fonction de la structure de votre équipe, de la taille de votre projet et de la manière dont vous gérez le développement de votre application, voire même si vous faîtes appel à des fournisseurs externes.

Mais gloabalement on peut dire que c’est l’équipe en charge du produit qui est en charge de mettre à jour régulièrement les dépendances.
Dans de nombreuses organisations, l’équipe de développement est responsable de maintenir et de mettre à jour les dépendances. Les développeurs surveillent régulièrement les mises à jour (on verra un peu plus tard comment le faire au travers d’outils), évaluent leur impact sur le projet et effectuent les mises à jour nécessaires.
Dans certaines entreprises, une équipe devops peut être chargée de gérer les mises à jour des dépendances, en particulier celles liées à l’infrastructure.

Généralement, les équipes de sécurité sont chargées de suivre les vulnérabilités et de veiller à ce que les correctifs nécessaires soient appliqués rapidement.

Le processus d’intégration continue et de déploiement continu (CI/CD) joue un rôle important afin d’automatiser au maximum dans vos pipelines CI/CD, les mises à jour des dépendances. Sans oublier les tests automatisés pour s’assurer que les mises à jour ne cassent pas le projet.

Dans une démarche DevOps / DevSecOps, c’est souvent une responsabilité partagée : dans de nombreuses équipes, la responsabilité de la mise à jour des dépendances est partagée entre les développeurs, les responsables de la sécurité, et les équipes opérationnelles.

Se pose aussi régulièrement la question : sur quel budget imputer ces actions ?
Il est crucial de considérer les mises à jour des dépendances comme des opérations de maintenance standard et normales, car elles contribuent à la stabilité, à la sécurité et à la performance de l’application. Ignorer ces mises à jour peut entraîner des risques de sécurité, des bugs et des problèmes de compatibilité. Par conséquent, allouer un budget adéquat, inclus dans le projet, pour ces activités est une décision avisée pour assurer la viabilité à moyens et longs termes de votre projet.

Dans tous les cas, il est essentiel de clarifier les rôles et les responsabilités au sein de votre équipe ou de votre organisation pour vous assurer que les mises à jour des dépendances sont prises en charge de manière efficace et responsable. Une communication claire et une collaboration entre les différentes parties prenantes sont essentielles pour garantir la sécurité et la stabilité de votre application.

Comment s’y prendre ?

Moins de dépendances !

La première chose à considérer est de réduire le nombre de dépendances : moins c’est mieux !
Quand on regarde le nombre de dépendances dans nos applications, c’est souvent effrayant. La plupart du temps, nos dépendances applicatives apportent bien plus que les fonctionnalités réellement utilisées. Tout comme nos images Docker sont souvent pleines de packages inutiles !
Faites le ménage et vous gagnerez en simplicité et facilité de maintenance, en sécurité, en stabilité et même en performances (tout à un coût) !

L’OWASP publie une liste de dix typologies de failles de sécurité, appelé le OWASP TOP 10. Celle qui nous intéresse aujourd’hui est la numéro 6 du classement 2021 "Les composants vulnérables et non mis à jour".
La question qui nous intéresse sera donc "Comment faire pour s’assurer que nos projets n’incluent pas de dépendances vulnérables ?".

Standardiser et mutualiser

Standardiser et mutualiser les dépendances dans la gestion des logiciels peuvent contribuer de manière significative à réduire l’effort de maintenance.

En standardisant et en mutualisant les dépendances, vous pouvez éviter la duplication des composants logiciels. Plutôt que d’avoir plusieurs instances de la même dépendance utilisées de manière disparate dans différents projets, vous pouvez centraliser l’utilisation de cette dépendance. Cela réduit le nombre total de dépendances, simplifiant ainsi la gestion.

La standardisation signifie aussi que vous utilisez les mêmes versions de dépendances dans l’ensemble de vos projets. Cela garantit l’uniformité et la cohérence entre les différentes parties de votre infrastructure logicielle. Il est plus facile de gérer et de maintenir un ensemble plus restreint de versions de dépendances.

Pour vos propres développements, avoir un système de versionning respectant certains principes comme le "Semantic versionning", un Release management reproductible et automatisé est indispensable pour mieux contrôler, simplifier et réduire vos coûts dans cette gestion des dépendances.

Cette mutualisation implique souvent d’avoir une ou plusieurs équipes expertes en charge de la gouvernance et de définir les règles de maintenance.

Des outils pour nous aider

L’approche manuelle

Aujourd’hui, beaucoup de langages inclus des gestionnaires de packages permettant de travailler les dépendances.
Il y a par exemple, Maven avec sont plugin "Versions" qui est utilisé lorsque vous souhaitez gérer les versions des artefacts dans le POM d’un projet.
En particulier la tâche "mvn versions:display-dependency-updates" recherche de nouvelles mises à jour des dépendances.

NPM inclut aussi un outil natif npm-audit qui soumet une description des dépendances configurées dans votre projet à votre registre par défaut et demande un rapport sur les vulnérabilités connues.
En particulier "npm audit fix" fait l’analyse pour détecter les vulnérabilités et installe automatiquement toutes les mises à jour compatibles pour les dépendances vulnérables.

Chaque langage va avoir ce type d’outil pour mettre à jour les dépendances obsolètes ou vulnérables, ce qui est déjà une bonne première étape mais cela reste une action relativement manuelle qu’un développeur doit faire ou alors une action à inclure dans sa pipeline qui sera accompagnée d’une étape bloquante de "quality gate". De plus, c’est dépendant de chaque langage et il faut aussi rajouter la partie container des dépendances systèmes et des images de base…

Mises à jour automatisées des dépendances. Multi-plateformes et multi-langues !

Pourquoi ne pas aller un cran plus loin et automatiser la détection des mises à jours des dépendances de vos applications ?
L’idée est de pouvoir détecter automatiquement, dans un repositorie Git, un ensemble de technologies, d’en déduire les mises à jour nécessaires et de déclencher automatiquement une Pull Request.

Dependabot

Par exemple, Dependabot est une application GitHub qui va accéder à vos repos au moyen d’un access token. Chaque jour, elle analysera les fichiers de dépendances (Java, JS, ou autre comme docker) et recherchera celles qui peuvent être mises à jour. Si l’une des dépendances est obsolète, Dependabot ouvre un Pull Request pour la remplacer. Il faut alors vérifier l’exécution des tests, analyser le changelog de la bibliothèque et prendre une décision. Puis accepter la mise à jour en mergeant la PR ou ignorer la nouvelle version.
A noter que Dependabot existe pour Github et Gitlab:

Renovate

Renovate a un fonctionnement similaire à Dependabot et fournit une version open source et entreprise.

Renovate va donc aussi scruter le code source de vos repositories pour vérifier s’il existe des mises à jour de dépendances. Si c’est le cas, il va créer automatiquement des Merge Requests pour leur mise à jour. En plus, si votre CI est complet et vos tests unitaires aussi, vous aurez une validation quasi automatique de ces modifications.

Il va aller un peu plus loin en fournissant des fonctionnalités plus avancées:

  • Réduction du bruit en exécutant Renovate selon un planning (les weekends, en dehors des heures de travail, chaque semaine, …)
  • Découverte automatique des fichiers de package pertinents
  • Prise en charge des architectures monorepo sans configuration supplémentaire
  • Personnalisation du bot en mode config as code
  • Utilisez des préréglages de configuration partagés de type ESLint pour une utilisation facile et une configuration simplifiée (format JSON uniquement)
  • Supporte des plateformes principales : Github, Gitlab, Bitbucket (Cloud ou server), Azure DevOps, AWS CodeCommit, …

Broken Chain

Tests de non régression obligatoires

L’automatisation de la mise à jour des dépendances ne peut fonctionner que si vous avez des tests de non régression sur lesquels s’appuyer.
Le but est de détecter des problèmes potentiels ou de confirmer la stabilité et donc de réduire les risques tout en accélérant le processus de mise à jour avec des coûts de maintenance maîtrisés.

Conclusion: la mise à jour régulière n’est pas une option !

La mise à jour régulière des dépendances est une étape cruciale dans la gestion de la sécurité, de la stabilité et de la performance de vos applications. Ignorer les mises à jour peut entraîner des vulnérabilités, des bugs et des problèmes de compatibilité qui peuvent avoir un impact négatif sur votre projet à long terme.

Le Top 10 OWASP met en lumière l’importance de la gestion des dépendances, notamment en ce qui concerne les composants vulnérables et obsolètes. Il est essentiel de suivre de près les mises à jour des dépendances et de prendre des mesures immédiates en cas de vulnérabilités critiques ou de correctifs de sécurité importants.

Cependant, la mise à jour des dépendances n’est pas une tâche simple. Elle demande du temps, des tests et une gestion appropriée pour minimiser les risques de perturbations. Il est crucial de considérer cela comme une opération de maintenance standard et de lui allouer un budget adéquat.

Pour rendre ce processus plus efficace, vous pouvez réduire le nombre de dépendances inutiles, standardiser et mutualiser les dépendances lorsque cela est possible, et automatiser la détection et la gestion des mises à jour grâce à des outils tels que Dependabot ou Renovate. Cependant, l’automatisation ne peut fonctionner efficacement que si vous avez des tests de non-régression en place pour garantir la stabilité de votre application.

En fin de compte, la mise à jour régulière de vos dépendances contribue à maintenir votre application à jour, sécurisée et en bonne santé, ce qui est essentiel pour répondre aux exigences changeantes du monde de la technologie et pour protéger votre projet des menaces émergentes, notamment les attaques de la chaîne d’approvisionnement (Supply Chain Attacks).

Laisser un commentaire

  Edit this page