Attaque par confusion de dépendances : comment ça marche et comment s'en prémunir

Les correctifs php2shell (CVE-2026-109618 et CVE-2026-109619) pour les versions de PHP en fin de vie sont désormais disponibles. Les réponses du service commercial étant plus lentes que d'habitude en raison d'une forte demande, le moyen le plus rapide d'obtenir les paquets corrigés est d'acheter ELS for Runtimes en ligne (s'ouvre dans un nouvel onglet). Consulter la FAQ sur les correctifs

Accédez directement au résumé généré par l'IA de cet article de blog

  • Résumez cet article avec Perplexity
  • Résume cet article avec Gemini

Dans le domaine du développement logiciel moderne, nous sommes passés d'un modèle d'installation strictement basé sur la chaîne d'approvisionnement à un modèle hybride. Les dépendances peuvent désormais être obtenues par deux voies : les paquets privés et les paquets publics. Cet article se penchera sur la confusion des dépendances et sur son lien avec les attaques par dépendance transitive profonde.

Le modèle de chaîne d'approvisionnement hybride

 

Today, we have two different ways of installing packages via various tools like npm, pnpm, etc. The concept of a single way to install packages is a thing of the past. Years ago, we would just open our terminal up and type npm install <package>. It would get pulled from the npm registry, and that would be that. Private packages, or scoped packages, can be delivered from the npm registry and are secure by default. You can also host scoped packages in internal registries like Nexus, Artifactory, and Verdaccio.

Un paquet avec une portée se présente comme suit : @myorg/mypackage. Il commence par le symbole « @ » suivi du nom de votre organisation, et se termine par une « / » et le nom du paquet. Il s'agit d'un paquet privé et sécurisé hébergé au sein du registre npm. Cela vous offre également la possibilité de regrouper des paquets au sein de votre organisation. Vous pouvez toujours installer des paquets publics qui sont également open source. Vous allez très certainement installer un paquet public afin de développer des fonctionnalités. Vous disposerez donc d’un mélange de paquets publics et privés.

La vulnérabilité s'installe insidieusement lorsque l'on utilise des paquets open source publics ou que la configuration CI/CD est inadéquate. Les gestionnaires de paquets ont été conçus pour faciliter la vie. Mais cette commodité a un coût. Ces gestionnaires privilégient les versions les plus récentes au détriment de la provenance du code source. C'est alors que les problèmes commencent à s'accumuler.

 

Qu'est-ce qu'une attaque par confusion de dépendances ?

 

Les attaques par confusion des dépendances exploitent la manière dont les gestionnaires de paquets modernes résolvent les dépendances provenant de plusieurs sources. Dans les environnements où l'on utilise à la fois des registres privés et publics, ce processus de résolution peut entraîner des risques inattendus.

Ce qui semble être une simple installation de dépendances peut en réalité servir de point d'entrée à du code malveillant, en particulier lorsque les paquets internes ne sont pas correctement isolés ou délimités.

Comment fonctionne la confusion liée à la dépendance

 

Une attaque par confusion de dépendances (ou confusion d'espaces de noms) exploite une faille dans la manière dont les gestionnaires de paquets résolvent les dépendances entre plusieurs registres. Elle se produit lorsqu'un système de compilation est configuré pour récupérer des paquets à la fois depuis un registre privé (interne) et depuis un registre public (comme npmjs.com).

Si un pirate identifie le nom d'un paquet privé sans portée et publie dans le registre public un paquet malveillant portant exactement le même nom mais avec un numéro de version supérieur, le gestionnaire de paquets considérera cette version publique et malveillante comme la « meilleure correspondance » et l'introduira silencieusement dans la chaîne d'approvisionnement. Cela s'explique par le fait que les gestionnaires de paquets donnent la priorité aux versions les plus récentes parmi les noms correspondants.

En pratique, les gestionnaires de paquets donnent la priorité à la version la plus récente qui satisfait aux plage , comme indiqué ci-dessus. Si votre fichier package.json demande la version ^1.2.0 de internal-tool, et l'attaquant publie la version v99.0.0 sur npmjs.com, le gestionnaire suppose que la version publique est une mise à jour légitime et la récupère.

Un autre cas de figure courant se présente lorsqu'une organisation n'utilise pas de paquets à portée limitée. Le paquet a été publié dans le registre privé sous le nom auth-package, mais il existe également un paquet portant le même nom dans le registre public. Le registre récupérera celui dont le numéro de version est le plus élevé, sauf indication contraire dans le fichier fichier .npmrc .

Décomposition des dépendances transitives

 

Une dépendance transitive est un paquet que vous, le développeur, n’avez pas installé intentionnellement, mais qui est installé automatiquement lorsque vous installez une dépendance directe pour un projet. Les dépendances transitives peuvent se cacher à plusieurs niveaux de profondeur dans l’arborescence des dépendances, ce qui rend difficile l’identification précise de l’origine des failles de sécurité.

« La plupart des incidents de cybersécurité étaient liés à des correctifs non installés. 60,4 % des incidents se sont produits alors qu'un correctif était disponible mais n'avait pas été installé. »

 

Pour lutter contre les failles de sécurité liées aux dépendances transitives dans la chaîne d'approvisionnement logicielle, il est essentiel de garder une longueur d'avance et d'appliquer les correctifs dès qu'ils sont disponibles. Vous trouverez ci-dessous un exemple illustrant ce qu'est une dépendance transitive.

rxjs est une dépendance directe d'Angular v20, mais si vous deviez fouiller dans le répertoire node_modules et que vous trouviez le fichier rxjs , vous verrez dans le fichier package.json le tslib . Ce paquet n'a pas été installé par vous, mais a été inclus dans le rxjs , dans le projet Angular v20.

Anatomie d'une attaque par confusion de dépendances

 

Prenons un composant d'interface utilisateur basique que vous souhaitez intégrer à un projet : un simple bouton. Ce bouton provient directement du système de conception de votre organisation et se trouve dans une bibliothèque de composants.

Rien de bien compliqué. Un arrière-plan, une police avec du texte et des coins arrondis. Ce bouton correspond exactement à ce qui est défini dans le système de conception. Le code est écrit en React et se présente ainsi :

 

export const DemoButton = () => {

  return (

    <button style={{ backgroundColor: 'blue', color: 'white' }}>

      Secure Scoped Action

    </button>

  );

};

 

On l'installe via npm, on l'importe dans notre projet, et le tour est joué. Un bouton fonctionnel dans notre interface utilisateur. D'un autre côté, il existe cependant un autre bouton sophistiqué , et ce bouton n’est soit pas limité au registre privé, soit il l’est, mais un développeur installe la version publique. C’est cette version publique qui est malveillante : elle déclenche des alertes sur la page d’accueil, intercepte les identifiants en arrière-plan ou inverse les couleurs du site, soit immédiatement, soit après un certain temps.

Le code de ce bouton se présente comme suit ; vous ne l'avez peut-être pas encore examiné :



import React, { useEffect } from 'react';



export const DemoButton = () => {

  useEffect(() => {

    document.body.style.filter = 'invert(100%)';

    alert("Hacked via Unscoped Dependency!");

  }, []);




  return <button>Click for Update</button>;

};

 

Il y a de fortes chances pour que ce bouton ne soit pas une dépendance directe. Dans l'exemple de code, je le présente comme une dépendance directe car je ne dispose pas encore d'un système de conception complet comprenant plusieurs composants. Si vous installez une bibliothèque d'interface utilisateur non vérifiée ou un paquet servant de dépendance pour votre système de conception, un bouton malveillant pourrait s'y introduire de manière transitive.

Qu'elles soient introduites directement ou de manière transitive, ces dépendances font partie intégrante de la zone de confiance de votre application – et constituent une surface d'attaque potentielle si elles ne sont pas contrôlées.

Attaques avant et après l'installation

 

Les pirates utilisent des et post-installation afin d'exécuter des charges utiles malveillantes avant même qu'un développeur n'ait le temps d'exécuter le code. La manière dont un script de pré-installation : avant que les fichiers du paquet ne soient placés dans votre dossier, le script peut effectuer des vérifications de l'environnement pour déterminer s'il doit exécuter un comportement malveillant. Si le script détecte un environnement renforcé ou surveillé, il envoie discrètement un message à son serveur d'origine et reste en veille pour éviter d'être détecté.

La script post-installation attend que la porte soit déverrouillée, puis toute une série d'événements peut se produire. Un script peut voler des secrets ou, pour reprendre les mots d’E.T., « téléphoner à la maison » et signaler au serveur que la porte est grande ouverte et que n’importe qui peut entrer. On peut faire le parallèle avec la légende des vampires. Une fois que vous avez invité un vampire à entrer, c’est la saison de la chasse.

Une fois que le script se trouve dans votre node_modules, il est trop tard : il s'exécute immédiatement. Le script exécute une commande telle que curl ou wget pour envoyer votre .env , vos clés SSH ou vos jetons AWS vers le site de l'attaquant. Une fois qu'il dispose de ces identifiants, vous ne pouvez pas faire grand-chose d'autre que supprimer vos clés/jetons et en régénérer de nouveaux.

Correction des conflits de dépendances

 

Il existe plusieurs façons de prendre les devants face à ces problèmes et de mettre en place un projet sécurisé et à jour. 

Paquets avec portée

Le moyen le plus sûr d'éviter une attaque par confusion de dépendances consiste à enregistrer votre organisation auprès du gestionnaire de paquets et à utiliser des paquets à portée limitée, @myorg/mypackage. Cela vous fournit un paquet sécurisé et privé qui peut être utilisé au sein de vos propres projets dans toute l'organisation.

Correct .npmrc Configurations

Lorsque vous créez votre .npmrc , veillez à associer strictement les champs spécifiques aux registres privés. En vous assurant qu’ils sont strictement associés, vous éviterez qu’ils ne « fuient » vers le registre public. Voici un exemple de fichier fichier .npmrc configuré à cet effet est présenté ci-dessous ; il s'agit de la méthode la plus efficace pour lutter contre les problèmes au sein de votre projet :

 

# Définir le registre par défaut pour les paquets publics

registry=https://registry.npmjs.org/




# Forcer tous les paquets de portée @org à être résolus UNIQUEMENT via le registre privé

@org:registry=https://npm.pkg.github.com/

always-auth=true

Utilisation de –ignore-scripts

Another clever way to get away from the preinstall and postinstall scripts is to use –ignore-scripts when installing packages. Using that flag looks like this: npm install <new-package> –ignore-scripts. This isn’t just something that is used once; you want to bake this into your automation and workflows as well.

Intégrité du fichier de verrouillage

Votre fichier package-lock.json ou yarn.lock ne se contente pas de verrouiller les versions ; il stocke un hachage, un hachage cryptographique. Si le hachage change et que la compilation échoue, cela signifie qu'un attaquant a remplacé le paquet dans le registre. En utilisant npm ci applique le fichier de verrouillage. Avec npm install, cette protection peut être contournée.

Sécuriser la pile

Compte tenu de tous ces éléments, veillez à respecter scrupuleusement une liste de contrôle de sécurité. Ces points n'en constituent qu'une partie.

 

  1. Utilisez des paquets à portée et veillez à enregistrer votre organisation dans le registre
  2. Configurez votre .npmrc pour associer strictement vos paquets au registre privé
  3. Utiliser –ignore-scripts dans vos pipelines CI/CD pour désactiver preinstall et postinstall par défaut

 

La sécurité de la chaîne d'approvisionnement n'est pas une tâche dont on peut se désintéresser une fois mise en place, comme un four à rôtissoire Ronco ; elle exige une vigilance constante à mesure que votre projet évolue. C'est un aspect dont il faut s'occuper dès le début et tout au long du projet, à mesure qu'il se développe.

Sécurisez vos registres, vérifiez vos périmètres et surveillez ce qui se passe au plus profond de votre arborescence de dépendances. Les risques les plus importants ne sont pas toujours visibles, mais ils se trouvent souvent déjà dans votre pile. Dans le même esprit que la métaphore du vampire qui n’est pas invité à entrer, je vous laisse sur cette citation tirée du film *The Lost Boys* : «Il y a une chose que je n’ai jamais pu supporter à Santa Carla : tous ces maudits vampires.» Santa Carla, c’est le logiciel, et les vampires, ce sont les failles de sécurité. Gardez une longueur d’avance et ne les laissez pas entrer.

 

Résumé
Attaque par confusion de dépendances : comment ça marche et comment s&#039;en prémunir
Nom de l'article
Attaque par confusion de dépendances : comment ça marche et comment s'en prémunir
Description
Découvrez comment fonctionnent les attaques par confusion de dépendances, comment elles exploitent npm et les dépendances transitives, et comment sécuriser votre chaîne logistique logicielle.
Auteur
Nom de l'éditeur
de TuxCare
Logo de l'éditeur

Rejoignez plus de 4 500 professionnels de Linux et de l'Open Source!

2 fois par mois. Pas de spam.

Table des matières
Obtenez les réponses à vos questions sur la sécurité des logiciels libres

Rejoignez plus de 4 500 professionnels de Linux et de l'Open Source!

2 fois par mois. Pas de spam.