La sécurité des applications web modernes ne repose plus uniquement sur la robustesse du code écrit en interne. Elle dépend de manière critique de l'intégrité de l'arbre des dépendances tierces. Dans l'écosystème Drupal, l'adoption généralisée de Composer a révolutionné la gestion des modules et des bibliothèques. Cependant, cette flexibilité introduit un vecteur d'attaque particulièrement redoutable : la confusion de dépendances, ou Dependency Confusion.
Ce guide technique détaille le fonctionnement de cette menace au sein des projets Drupal d'entreprise et fournit des solutions concrètes pour verrouiller vos processus d'intégration continue et vos serveurs de production.

Comprendre le mécanisme de l'attaque par confusion de dépendances
Pour contrer efficacement une menace, il est nécessaire de comprendre précisément comment elle s'opère. Dans le cadre de la confusion de dépendances, l'attaquant exploite le comportement par défaut des gestionnaires de paquets.
Le rôle de l'algorithme de résolution de Composer
Par défaut, lorsqu'un projet nécessite un paquet, Composer interroge l'ensemble des dépôts déclarés dans le fichier de configuration. Si un même paquet est présent sur plusieurs dépôts (par exemple, sur un dépôt Gitlab privé et sur le registre public Packagist), Composer applique un algorithme de résolution basé principalement sur la version.
L'outil privilégie systématiquement la version la plus élevée disponible, quelle que soit la source. Si un attaquant parvient à identifier le nom d'un module privé utilisé par votre entreprise et l'enregistre sur Packagist avec un numéro de version très élevé, Composer téléchargera la version malveillante publique lors de la prochaine mise à jour.
Le cas d'usage typique d'un module Drupal personnalisé
Prenons l'exemple d'une grande entreprise qui développe un module Drupal sur mesure nommé mon-agence/drupal-custom-auth. Ce module est stocké sur un dépôt Gitlab interne et configuré dans le projet d'entreprise.
Un attaquant externe analyse les fichiers de configuration publics (parfois exposés par erreur ou présents dans des dépôts de code ouverts) et découvre ce nom de paquet. Il publie alors sur Packagist un script malveillant sous le nom exact mon-agence/drupal-custom-auth avec la version 999.0.0. Lors du prochain build d'intégration continue, Composer interrogera Packagist, constatera que la version 999.0.0 est supérieure à votre version locale et installera le code de l'attaquant sur votre serveur d'intégration ou de production.
Durcir la configuration du fichier composer.json
La méthode la plus efficace pour bloquer cette attaque consiste à modifier la manière dont Composer interroge et priorise vos dépôts de paquets.
Configurer des dépôts privés canoniques
Par défaut, les dépôts déclarés dans Composer ne sont pas canoniques. Cela signifie que Composer continuera à chercher un paquet sur Packagist même s'il l'a déjà trouvé dans votre dépôt privé. Pour corriger cela, il faut déclarer explicitement votre dépôt privé comme étant canonique.
Voici un exemple de configuration sécurisée à intégrer dans votre fichier de configuration :
{
"name": "mon-agence/projet-drupal",
"description": "projet Drupal securise d entreprise",
"repositories": [
{
"type": "composer",
"url": "[https://composer.mon-registre-prive.fr](https://composer.mon-registre-prive.fr)",
"canonical": true
}
],
"require": {
"php": ">=8.2",
"drupal/core-recommended": "^10.1",
"mon-agence/drupal-custom-auth": "^1.0"
},
"config": {
"allow-plugins": {
"composer/installers": true,
"drupal/core-composer-scaffold": true
}
}
}
En ajoutant l'instruction "canonical": true sur votre dépôt privé, vous indiquez à Composer que si le paquet demandé est présent sur ce dépôt, il ne doit sous aucun prétexte chercher des versions alternatives sur d'autres registres comme Packagist.
Utiliser les filtres d'exclusion de paquets
Si vous utilisez des dépôts tiers ou des répertoires de types différents, vous pouvez configurer des règles strictes de filtrage. Cela permet d'interdire formellement à Packagist de répondre aux requêtes concernant les namespaces internes de votre organisation.
Voici comment structurer vos exclusions pour protéger vos modules spécifiques :
{
"repositories": [
{
"type": "composer",
"url": "[https://packages.drupal.org/8](https://packages.drupal.org/8)",
"exclude": [
"mon-agence/drupal-custom-auth",
"mon-agence/drupal-custom-theme"
]
},
{
"type": "composer",
"url": "[https://repo.packagist.org](https://repo.packagist.org)",
"exclude": [
"mon-agence/drupal-custom-auth",
"mon-agence/drupal-custom-theme"
]
}
]
}
Cette approche garantit que les requêtes concernant vos paquets internes ne quitteront jamais votre réseau local ou vos serveurs de build privés, empêchant ainsi toute interception ou substitution.

Industrialisation et automatiser l'audit en intégration continue
La sécurisation locale du fichier de configuration ne suffit pas : elle doit être validée et imposée à chaque étape du cycle de vie logiciel via vos pipelines de déploiement.
Intégrer l'audit de sécurité dans les pipelines CI-CD
L'outil de build doit exécuter des vérifications systématiques avant d'autoriser tout déploiement sur vos serveurs cibles, qu'ils soient hébergés chez AWS ou OVHcloud.
Voici un exemple de configuration de pipeline d'intégration continue sous Debian pour valider l'arbre des dépendances :
# Pipeline de validation de securite Composer
stages:
- test
- security
validate_composer:
stage: test
image: composer:2.6
script:
// Verifier que le fichier lock est parfaitement synchrone avec le json
- composer validate --no-check-publish --strict
// Verifier l absence de dependances non securisees connues
- composer audit --format=json
audit_dependencies:
stage: security
image: debian:bookworm-slim
before_script:
- apt-get update && apt-get install -y php-cli unzip curl
- curl -sS [https://getcomposer.org/installer](https://getcomposer.org/installer) | php -- --install-dir=/usr/local/bin --filename=composer
script:
// Analyse approfondie des dependances du projet
- composer show --locked
Cette configuration de pipeline garantit que toute modification suspecte dans le fichier de verrouillage sera immédiatement détectée et bloquera le déploiement.
Valider l'intégrité des fichiers de verrouillage sous Debian
Dans vos environnements de production sous Debian, l'installation des dépendances ne doit jamais utiliser la commande classique de mise à jour. Utilisez toujours la commande d'installation stricte qui s'appuie uniquement sur le fichier de verrouillage existant.
La commande suivante doit être privilégiée lors de vos déploiements automatisés :
# Executer l installation de production sans interaction et de maniere stricte
composer install --no-dev --optimize-autoloader --no-interaction --frozen-lockfileCette commande empêche Composer de recalculer l'arbre des dépendances à la volée sur le serveur de production, éliminant ainsi le risque d'introduire un nouveau paquet non testé.
Comparaison des approches de sécurisation de Composer
Pour vous aider à choisir la meilleure stratégie selon votre infrastructure, voici une analyse comparative des différentes méthodes de protection disponibles :
- L'utilisation de dépôts canoniques :
- Niveau de sécurité : excellent.
- Complexité de mise en œuvre : très faible.
- Impact sur les performances : négligeable.
- Recommandation : obligatoire pour tous les projets d'entreprise utilisant des modules internes.
- Le filtrage par exclusion explicite :
- Niveau de sécurité : très élevé.
- Complexité de mise en œuvre : moyenne.
- Impact sur les performances : aucun.
- Recommandation : idéale si vous utilisez de nombreux dépôts tiers en plus de Packagist.
- La désactivation complète de Packagist :
- Niveau de sécurité : maximal.
- Complexité de mise en œuvre : élevée.
- Impact sur les performances : nécessite un proxy local.
- Recommandation : réservée aux environnements hautement sécurisés ou sous contraintes réglementaires fortes.
FAQ : sécuriser vos dépendances PHP et Drupal
Comment savoir si mon projet Drupal est actuellement vulnérable ?
Vérifiez si votre fichier de configuration contient des modules personnalisés sans dépôt privé associé configuré comme canonique. Si Composer doit chercher vos packages internes sur les registres publics par défaut, votre projet présente un risque.
Est-ce que Composer 2 est nativement protégé contre la confusion de dépendances ?
Composer 2 introduit des avertissements clairs et permet de configurer facilement des dépôts canoniques, mais il ne bloque pas par défaut l'installation d'un paquet public si aucune règle stricte de filtrage ou de canonicité n'a été rédigée dans votre configuration.
Quel est l'impact de l'option repo.packagist: false ?
Cette option désactive complètement le dépôt public Packagist. Cela signifie que vous devez héberger ou déclarer manuellement l'intégralité des dépendances de votre projet sur vos propres serveurs, ce qui élimine totalement le risque mais augmente la maintenance.
Pourquoi utiliser l'option --frozen-lockfile en production ?
Cette option force l'installation à échouer si le fichier de verrouillage n'est pas parfaitement à jour par rapport aux modifications récentes du fichier principal, évitant ainsi des installations de paquets non validés durant l'intégration continue.