La correction des vulnérabilités indirectes fait partie de ces tâches complexes, fastidieuses et franchement ennuyeuses auxquelles personne ne veut vraiment s’atteler. Personne sauf pour Débriqué, il semble. Bien sûr, il existe de nombreuses façons de le faire manuellement, mais peut-il être fait automatiquement avec un risque minimal de rupture des modifications ? L’équipe Debricked a décidé de le découvrir.
Une forêt pleine d’arbres fragiles
Alors, par où commencer ?
Premièrement, il doit y avoir un moyen de corriger la vulnérabilité, ce qui, pour les dépendances indirectes, n’est pas une promenade de santé. Deuxièmement, cela doit être fait de manière sûre ou sans rien casser.
Vous voyez, les dépendances indirectes sont introduites profondément dans l’arborescence des dépendances et il est très difficile d’obtenir la version exacte que vous souhaitez. Comme l’a dit un jour le responsable de la R&D de Debricked, « Vous tournez les boutons en jouant avec vos dépendances directes et en priant Torvalds pour que les bons paquets indirects soient résolus. Lorsque Torvalds est en votre faveur, vous devez sacrifier un peu de stockage cloud à l’oncle Bob pour vous assurer que les mises à jour ne cassent pas votre application. »
En d’autres termes, il devrait vraiment y avoir un moyen plus simple et moins stressant de le faire.
Dans cet article, nous vous expliquerons comment résoudre manuellement les vulnérabilités transitives et, vers la fin, nous vous montrerons la solution Debricked, qui vous permet de le faire automatiquement. Si vous êtes vraiment intéressé par la solution, je vous suggère de commencer à faire défiler.
Chirurgie de précision sur votre arbre de dépendance
Au cours de la phase de recherche du projet de base de données graphiqueou comment Debricked corrige aujourd’hui vos vulnérabilités open source à la vitesse de la lumière, l’équipe est tombée sur quelques articles expliquant comment corriger les vulnérabilités indirectes dans NPM.
Comme indiqué dans l’article, le package « minimist » est affecté par des vulnérabilités, à savoir CVE-2021-44906 et CVE-2020-7598.
Il s’agit de deux vulnérabilités « Pollution prototype », ce qui signifie que les arguments ne sont pas correctement filtrés. Heureusement, les responsables de `minimist` ont corrigé ces vulnérabilités dans la version 1.2.6.
Malheureusement, la version 7.1.0 de `mocha` résout `minimist` 0.0.8, qui se situe dans la plage vulnérable de ces vulnérabilités. Comme l’a suggéré l’auteur de Cet articleces vulnérabilités peuvent être corrigées de différentes manières.
Mais! Qu’en est-il des modifications avec rupture ?
La première suggestion est de simplement déclencher une mise à jour de toutes les « dépendances indirectes », ce qui signifie que nous ne changerons pas réellement la version de `mocha`. Pour effectuer cette mise à jour, exécutez simplement `npm update`, supprimez votre fichier `npm.lock` et exécutez `npm install`. Cela régénère l’arborescence des dépendances avec la dernière version possible (selon les contraintes) de vos dépendances indirectes. Avec cette méthode, le risque de casser les changements est très faible car vous ne mettez à jour aucune de vos dépendances racine, seulement vos dépendances indirectes.
Des modifications avec rupture se produisent lorsque la fonctionnalité ou l’interface du package n’est pas compatible avec les versions ultérieures, ce qui signifie qu’une mise à jour du package peut entraîner la rupture de votre application. Les changements de rupture courants sont la suppression de classe/fonction, le changement d’arguments d’une fonction ou le changement de licence (attention à celui-là !).
Mais la vie n’est pas toujours aussi facile, et cette simple mise à jour de l’arbre ne résoudra pas la vulnérabilité. Le problème est que `mkdirp` a en fait verrouillé sa version de `minimist` à 0.0.8. Cela signifie que les contributeurs de `mkdirp` sont arrivés à la conclusion qu’ils ne sont pas compatibles avec les nouvelles versions de `minimist`, et forcer la mise à jour de `minimist` peut introduire des changements de rupture entre `mkdirp` et `minimist`.
Pensez… aux graphiques !
Donc, la question à un million de dollars est : quelle version de « moka » doit être utilisée, qui à son tour se transforme en une version sûre de « minimist » sans casser l’arbre de dépendance ? Il s’agit en fait d’un problème de graphe, qui a été décrit dans Cet article.
Quel algorithme de graphe résoudrait ce problème ? La façon dont NPM résout les dépendances peut être un peu compliquée, car ils sont autorisés à « diviser » l’arborescence des dépendances. Cela signifie qu’ils peuvent avoir plusieurs versions d’une dépendance pour s’assurer que nous avons toujours un arbre compatible. Pour résoudre la vulnérabilité, nous devons nous assurer que toutes les instances de `minimist` sont sûres en mettant à jour toutes les racines qui peuvent se répercuter sur `minimist`.
L’algorithme utilisé pour résoudre ce problème s’appelle « All Max Paths Safe ». En parcourant le graphique des dépendances et en conservant le nombre maximal de versions, tout en supprimant toutes les autres versions de ce package à chaque intersection, nous pouvons créer une représentation approximative de notre arbre de dépendances. Si l’approximation est sûre, cela signifie que notre arbre réel sera également sûr !
En exécutant cet algorithme pour toutes les versions potentielles de `mocha`, nous trouvons la plus petite mise à jour pour corriger cette vulnérabilité. Pour obtenir la vitesse que nous voulions pour cet algorithme, l’équipe a dû créer un Procédure Neo4j, qui peut gérer la recherche de plus de 100 versions root avec une profondeur de recherche de 30+ en ~150 millisecondes. Rapide, hein ?
Dans ce cas, nous n’avons pas besoin de chercher très loin… car la version 7.1.1 de `mocha` est sûre ! Il ne s’agit que d’une mise à jour de correctif, ce qui indique que le risque de casser les modifications est très faible. Pour les cas moins complexes (comme cet exemple), ‘npm audit’ peut vous aider avec sa fantastique commande ‘npm audit fix’.
Ne soyez pas ad hoc, entrez dans la façon de travailler pub-sous-humaine !
Maintenant, si vous êtes arrivé jusqu’ici (félicitations, très impressionnant) et que vous pensez, « cela semble vraiment complexe et représente énormément de travail », ne vous inquiétez pas – vous n’êtes pas le seul. Heureusement, tout cela se produit de manière entièrement automatique dans l’outil Debricked lorsque vous cliquez sur ce petit bouton :
À partir de maintenant, ceci est disponible pour Javascript. Bientôt, le support sera étendu à Java, Golang, C#, Python et PHP.
Si vous n’êtes pas encore un Débriqué utilisateur, qu’attendez-vous ? C’est gratuit pour les développeurs individuels, les petites équipes et les projets open source (et si vous êtes une grande organisation, n’ayez crainte. Il y a un essai gratuit généreux). Inscrivez-vous gratuitement ici.