Translated ['', 'src/pentesting-web/dependency-confusion.md'] to fr

This commit is contained in:
Translator 2025-08-21 02:40:25 +00:00
parent f9d3a8d706
commit 7be520f22b

View File

@ -5,41 +5,270 @@
## Informations de Base
En résumé, une vulnérabilité de confusion de dépendance se produit lorsqu'un projet utilise une bibliothèque avec un **nom mal orthographié**, **inexistante** ou avec une **version non spécifiée** et le dépôt de dépendances utilisé permet de **rassembler des versions mises à jour à partir de dépôts publics**.
La Confusion de Dépendance (a.k.a. attaques de substitution) se produit lorsqu'un gestionnaire de paquets résout un nom de dépendance à partir d'un registre/source non intentionnel et moins fiable (généralement un registre public) au lieu du registre interne/privé prévu. Cela conduit généralement à l'installation d'un paquet contrôlé par un attaquant.
Causes racines courantes :
- Typosquatting/misspelling : Importation de `reqests` au lieu de `requests` (résout à partir du registre public).
- Paquet interne inexistant/abandonné : Importation de `company-logging` qui n'existe plus en interne, donc le résolveur cherche dans les registres publics et trouve un paquet de l'attaquant.
- Préférence de version à travers plusieurs registres : Importation d'un `company-requests` interne alors que le résolveur est autorisé à interroger également des registres publics et préfère la version "meilleure"/plus récente publiée publiquement par un attaquant.
Idée clé : Si le résolveur peut voir plusieurs registres pour le même nom de paquet et est autorisé à choisir le "meilleur" candidat globalement, vous êtes vulnérable à moins de contraindre la résolution.
- **Mal orthographié** : Importer **`reqests`** au lieu de `requests`
- **Inexistante** : Importer `company-logging`, une bibliothèque interne qui **n'existe plus**
- **Version non spécifiée** : Importer une bibliothèque `company-requests` **interne** **existante**, mais le dépôt vérifie les **dépôts publics** pour voir s'il existe des **versions supérieures**.
## Exploitation
> [!WARNING]
> Dans tous les cas, l'attaquant doit simplement publier un **package malveillant avec le nom** des bibliothèques utilisées par l'entreprise victime.
> Dans tous les cas, l'attaquant n'a besoin que de publier un paquet malveillant portant le même nom que la dépendance que votre build résout à partir d'un registre public. Les hooks au moment de l'installation (par exemple, les scripts npm) ou les chemins de code au moment de l'importation donnent souvent une exécution de code.
### Mal Orthographié & Inexistant
### Mal Épelé & Inexistant
Si votre entreprise essaie d'**importer une bibliothèque qui n'est pas interne**, il est très probable que le dépôt de bibliothèques va la rechercher dans des **dépôts publics**. Si un attaquant l'a créée, votre code et les machines en cours d'exécution seront très probablement compromis.
Si votre projet fait référence à une bibliothèque qui n'est pas disponible dans le registre privé, et que vos outils se rabattent sur un registre public, un attaquant peut semer un paquet malveillant avec ce nom dans le registre public. Vos machines de runners/CI/dev le récupéreront et l'exécuteront.
### Version Non Spécifiée
### Version Non Spécifiée / Sélection de "Meilleure Version" à travers les Index
Les développeurs laissent souvent les versions non fixées ou permettent des plages larges. Lorsqu'un résolveur est configuré avec des index internes et publics, il peut sélectionner la version la plus récente indépendamment de la source. Pour des noms internes comme `requests-company`, si l'index interne a `1.0.1` mais qu'un attaquant publie `1.0.2` dans le registre public et que votre résolveur considère les deux, le paquet public peut l'emporter.
Il est très courant que les développeurs **ne spécifient aucune version** de la bibliothèque utilisée, ou spécifient juste une **version majeure**. Ensuite, l'interpréteur essaiera de télécharger la **dernière version** correspondant à ces exigences.\
Si la bibliothèque est une **bibliothèque externe connue** (comme `requests` de python), un **attaquant ne peut pas faire grand-chose**, car il ne pourra pas créer une bibliothèque appelée `requests` (à moins qu'il ne soit l'auteur original).\
Cependant, si la bibliothèque est **interne**, comme `requests-company` dans cet exemple, si le **dépôt de la bibliothèque** permet de **vérifier les nouvelles versions également de manière externe**, il recherchera une version plus récente disponible publiquement.\
Donc, si un **attaquant sait** que l'entreprise utilise la bibliothèque `requests-company` **version 1.0.1** (permettant des mises à jour mineures). Il peut **publier** la bibliothèque `requests-company` **version 1.0.2** et l'entreprise **utilisera cette bibliothèque à la place** de l'interne.
## Correction AWS
Cette vulnérabilité a été trouvée dans AWS **CodeArtifact** (lisez les [**détails dans cet article de blog**](https://zego.engineering/dependency-confusion-in-aws-codeartifact-86b9ff68963d)).\
AWS a corrigé cela en permettant de spécifier si une bibliothèque est interne ou externe, pour éviter de télécharger des dépendances internes à partir de dépôts externes.
Cette vulnérabilité a été trouvée dans AWS CodeArtifact (lisez les détails dans cet article de blog). AWS a ajouté des contrôles pour marquer les dépendances/flux comme internes ou externes afin que le client ne récupère pas les noms "internes" des registres publics en amont.
## Trouver des Bibliothèques Vulnérables
Dans le [**post original sur la confusion de dépendance**](https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610), l'auteur a recherché des milliers de fichiers package.json exposés contenant les dépendances de projets javascript.
Dans le post original sur la confusion de dépendance, l'auteur a recherché des milliers de manifests exposés (par exemple, `package.json`, `requirements.txt`, fichiers de verrouillage) pour inférer des noms de paquets internes et a ensuite publié des paquets de version supérieure dans des registres publics.
## Manuel Pratique de l'Attaquant (pour les équipes rouges lors de tests autorisés)
- Énumérer les noms :
- Grep les dépôts et les configurations CI pour des fichiers manifestes/fichiers de verrouillage et des espaces de noms internes.
- Rechercher des préfixes spécifiques à l'organisation (par exemple, `@company/*`, `company-*`, groupIds internes, modèles d'ID NuGet, chemins de modules privés pour Go, etc.).
- Vérifier la disponibilité dans les registres publics :
- Si le nom n'est pas enregistré publiquement, enregistrez-le ; s'il existe, tentez de détourner la sous-dépendance en ciblant des noms transitoires internes.
- Publier avec priorité :
- Choisissez un semver qui "gagne" (par exemple, une version très élevée) ou qui correspond aux règles du résolveur.
- Inclure une exécution minimale au moment de l'installation lorsque cela est applicable (par exemple, scripts npm `preinstall`/`install`/`postinstall`). Pour Python, préférez les chemins d'exécution au moment de l'importation, car les roues n'exécutent généralement pas de code arbitraire lors de l'installation.
- Exfiltrer le contrôle :
- Assurez-vous que les sorties sont autorisées de CI vers votre point de terminaison contrôlé ; sinon, utilisez des requêtes DNS ou des messages d'erreur comme canal secondaire pour prouver l'exécution de code.
> [!CAUTION]
> Obtenez toujours une autorisation écrite, utilisez des noms/versions de paquets uniques pour l'engagement, et dépubliez immédiatement ou coordonnez le nettoyage lorsque les tests sont terminés.
## Manuel du Défenseur (ce qui empêche réellement la confusion)
Stratégies de haut niveau qui fonctionnent à travers les écosystèmes :
- Utilisez des espaces de noms internes uniques et liez-les à un seul registre.
- Évitez de mélanger les niveaux de confiance au moment de la résolution. Préférez un seul registre interne qui proxy les paquets publics approuvés au lieu de donner aux gestionnaires de paquets à la fois des points de terminaison internes et publics.
- Pour les gestionnaires qui le supportent, mappez les paquets à des sources spécifiques (pas de "meilleure version" globale à travers les registres).
- Fixez et verrouillez :
- Utilisez des fichiers de verrouillage qui enregistrent les URL de registre résolues (npm/yarn/pnpm) ou utilisez le pinning par hachage/attestation (pip `--require-hashes`, vérification de dépendance Gradle).
- Bloquez le retour public pour les noms internes au niveau du registre/réseau.
- Réservez vos noms internes dans les registres publics lorsque cela est possible pour prévenir les futurs squats.
## Notes sur l'Écosystème et Extraits de Configuration Sécurisée
Voici des configurations pragmatiques et minimales pour réduire ou éliminer la confusion de dépendance. Préférez les appliquer dans les environnements CI et de développement.
### JavaScript/TypeScript (npm, Yarn, pnpm)
- Utilisez des paquets scoppés pour tout le code interne et fixez la portée à votre registre privé.
- Gardez les installations immuables dans CI (fichier de verrouillage npm, `yarn install --immutable`).
.npmrc (niveau projet)
```
# Bind internal scope to private registry; do not allow public fallback for @company/*
@company:registry=https://registry.corp.example/npm/
# Always authenticate to the private registry
//registry.corp.example/npm/:_authToken=${NPM_TOKEN}
strict-ssl=true
```
package.json (pour le package interne)
```
{
"name": "@company/api-client",
"version": "1.2.3",
"private": false,
"publishConfig": {
"registry": "https://registry.corp.example/npm/",
"access": "restricted"
}
}
```
Yarn Berry (.yarnrc.yml)
```
npmScopes:
company:
npmRegistryServer: "https://registry.corp.example/npm/"
npmAlwaysAuth: true
# CI should fail if lockfile would change
enableImmutableInstalls: true
```
Conseils opérationnels :
- Publiez uniquement des packages internes dans le scope `@company`.
- Pour les packages tiers, autorisez le registre public via votre proxy/miroir privé, pas directement depuis les clients.
- Envisagez d'activer la provenance des packages npm pour les packages publics que vous publiez afin d'augmenter la traçabilité (cela ne prévient pas en soi la confusion).
### Python (pip / Poetry)
Règle de base : N'utilisez pas `--extra-index-url` pour mélanger les niveaux de confiance. Soit :
- Exposez un seul index interne qui proxy et met en cache les packages PyPI approuvés, ou
- Utilisez une sélection d'index explicite et un hachage fixe.
pip.conf
```
[global]
index-url = https://pypi.corp.example/simple
# Disallow source distributions when possible
only-binary = :all:
# Lock with hashes generated via pip-tools
require-hashes = true
```
Générez des exigences hachées avec pip-tools :
```
# From pyproject.toml or requirements.in
pip-compile --generate-hashes -o requirements.txt
pip install --require-hashes -r requirements.txt
```
Si vous devez accéder à PyPI public, faites-le via votre proxy interne et maintenez une liste d'autorisation explicite. Évitez `--extra-index-url` dans CI.
### .NET (NuGet)
Utilisez le mappage des sources de packages pour lier les modèles d'ID de package à des sources explicites et empêcher la résolution à partir de flux inattendus.
nuget.config
```
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="corp" value="https://nuget.corp.example/v3/index.json" />
</packageSources>
<packageSourceMapping>
<packageSource key="nuget.org">
<package pattern="*" />
</packageSource>
<packageSource key="corp">
<package pattern="Company.*" />
<package pattern="Internal.Utilities" />
</packageSource>
</packageSourceMapping>
</configuration>
```
### Java (Maven/Gradle)
Maven settings.xml (miroir tout vers interne ; interdire les dépôts ad-hoc dans les POMs via Enforcer) :
```
<settings>
<mirrors>
<mirror>
<id>internal-mirror</id>
<mirrorOf>*</mirrorOf>
<url>https://maven.corp.example/repository/group</url>
</mirror>
</mirrors>
</settings>
```
Ajoutez Enforcer pour interdire les dépôts déclarés dans les POM et forcer l'utilisation de votre miroir :
```
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.6.1</version>
<executions>
<execution>
<id>enforce-no-repositories</id>
<goals><goal>enforce</goal></goals>
<configuration>
<rules>
<requireNoRepositories />
</rules>
</configuration>
</execution>
</executions>
</plugin>
```
Gradle : Centraliser et verrouiller les dépendances.
- Appliquer les dépôts uniquement dans `settings.gradle(.kts)` :
```
dependencyResolutionManagement {
repositoriesMode = RepositoriesMode.FAIL_ON_PROJECT_REPOS
repositories {
maven { url = uri("https://maven.corp.example/repository/group") }
}
}
```
- Activez la vérification des dépendances (checksums/signatures) et validez `gradle/verification-metadata.xml`.
### Go Modules
Configurez des modules privés afin que le proxy public et la base de données de checksums ne soient pas utilisés pour eux.
```
# Use corporate proxy first, then public proxy as fallback
export GOPROXY=https://goproxy.corp.example,https://proxy.golang.org
# Mark private paths to skip proxy and checksum db
export GOPRIVATE=*.corp.example.com,github.com/your-org/*
export GONOSUMDB=*.corp.example.com,github.com/your-org/*
```
### Rust (Cargo)
Remplacez crates.io par un miroir interne approuvé ou un répertoire de fournisseurs pour les builds ; ne permettez pas de repli public arbitraire.
.cargo/config.toml
```
[source.crates-io]
replace-with = "corp-mirror"
[source.corp-mirror]
registry = "https://crates-mirror.corp.example/index"
```
Pour la publication, soyez explicite avec `--registry` et gardez les identifiants limités au registre cible.
### Ruby (Bundler)
Utilisez des blocs source et désactivez les Gemfiles multisource afin que les gems proviennent uniquement du dépôt prévu.
Gemfile
```
source "https://gems.corp.example"
source "https://rubygems.org" do
gem "rails"
gem "pg"
end
source "https://gems.corp.example" do
gem "company-logging"
end
```
Appliquer au niveau de la configuration :
```
bundle config set disable_multisource true
```
## CI/CD et contrôles de registre qui aident
- Registre privé comme point d'entrée unique :
- Utilisez Artifactory/Nexus/CodeArtifact/GitHub Packages/Azure Artifacts comme le seul point d'accès que les développeurs/CI peuvent atteindre.
- Mettez en œuvre des règles de blocage/autorisation afin que les espaces de noms internes ne se résolvent jamais à partir de sources publiques en amont.
- Les fichiers de verrouillage sont immuables dans CI :
- npm : validez `package-lock.json`, utilisez `npm ci`.
- Yarn : validez `yarn.lock`, utilisez `yarn install --immutable`.
- Python : validez `requirements.txt` haché, appliquez `--require-hashes`.
- Gradle : validez `verification-metadata.xml` et échouez sur les artefacts inconnus.
- Contrôle de sortie sortante : bloquez l'accès direct de CI aux registres publics sauf via le proxy approuvé.
- Réservation de nom : préenregistrez vos noms/espaces de noms internes dans les registres publics où cela est pris en charge.
- Provenance des paquets / attestations : lors de la publication de paquets publics, activez la provenance/attestations pour rendre la falsification plus détectable en aval.
## Références
- [https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610](https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610)
- [https://zego.engineering/dependency-confusion-in-aws-codeartifact-86b9ff68963d](https://zego.engineering/dependency-confusion-in-aws-codeartifact-86b9ff68963d)
- [https://learn.microsoft.com/en-us/nuget/consume-packages/package-source-mapping](https://learn.microsoft.com/en-us/nuget/consume-packages/package-source-mapping)
- [https://yarnpkg.com/configuration/yarnrc/](https://yarnpkg.com/configuration/yarnrc/)
{{#include ../banners/hacktricks-training.md}}