Bei der Softwareentwicklung sind wir sowohl auf eigene als auch auf fremde Komponenten oder Artefakte angewiesen. Ein flexibles Abhängigkeitsmanagement ist für moderne Software unerlässlich. Paketmanager wie NPM, Maven, Pip or NuGet werden häufig verwendet, um Softwareabhängigkeiten anzugeben. Diese Tools wurden mit Blick auf Benutzerfreundlichkeit und Benutzerfreundlichkeit entwickelt, nicht auf Sicherheit.
Das Problem
Das Problem ist, dass Flexibilität und Benutzerfreundlichkeit für Entwickler die Bösewichte anlocken, die Softwareabhängigkeiten als unwiderstehlichen Reiz für ihr Geschäft betrachten. Das Ergebnis: Böse Akteure verfolgten alle hier gezeigten möglichen Angriffspfade. Quelle: „Backstabber's Knife Collection: A Review of Open Source Software Supply Chain Attacks“
In diesem Beitrag konzentrieren wir uns auf die Verwendung offener Versionsdeklarationen in dem Sinne, dass die heruntergeladene Version nicht festgelegt ist, sondern einem bestimmten Bereich angehören muss. Zur Build-Zeit wird die höchste vorhandene Version, die mit dem angegebenen Versionsbereich kompatibel ist, vom Paketmanager ausgewählt und heruntergeladen/installiert.
Lassen Sie uns offene Deklarationen in Abhängigkeitsdeklarationen für verschiedene Paketmanager veranschaulichen:
-
- NPM: paket.json
{
...
„Abhängigkeiten“: {
...
„akzeptiert“: „>=1.3.8“,
„lodash“: „~4.16.0“,
...
},
...
}
Es wird die größte vorhandene Version nicht unter 1.3.8 für das Accepts-Paket installiert, sowie das größte „Patch“-Update für Lodash im Bereich 4.16.x.
-
- Maven: pom.xml
...
...
commons-io
commons-io
FREIGEBEN
...
...
Die letzte verfügbare Version für Commons-IO (JAR-Datei) wird als Abhängigkeit hinzugefügt.
-
- Pip: setup.py
...
aufstellen(
...
install_requires=['peppercorn', 'launchpadlib'],
...
)
...
Solche offenen Versionsschemata haben eine gute und eine schlechte Seite. Die gute ist, dass neuere Versionen gewöhnlich enthalten Funktions- und Qualitätsverbesserungen, Fehlerbehebungen und Sicherheitspatches, die automatisch aktualisiert werden. Bitte beachten Sie, dass bei den meisten realen Projekten Korrekturen nicht auf frühere Nebenversionen zurückportiert werden, außer vielleicht bei katastrophalen Sicherheitslücken. Offene Versionen eignen sich auch gut für die Verwendung in Bibliotheken, um die Anzahl der Versionen zu reduzieren, die installiert werden müssen, wenn alle Abhängigkeiten aufgelöst sind.
Offene Versionsbereiche haben jedoch eine schlechte Seite. Sie wissen nicht genau, welche Versionen zum Zeitpunkt des Builds installiert werden, und Builds sind nicht wiederholbar. Und es gibt auch eine dunkel Seite mit offenen Versionen. Wenn es einem böswilligen Akteur gelingt, eine bösartige Komponente im öffentlichen Repository mit einer hohen Version zu veröffentlichen, die mit Ihrem offenen Bereich kompatibel ist, wird Ihr nächster Build die bösartige Komponente enthalten und möglicherweise sogar Malware in Installationsskripten ausführen, die möglicherweise automatisch ausgeführt werden. Die Verschleierung der Angriffsnutzlast ist eine Kunst.
Dies ist bekannt als die Fehlende Versionsfixierung Problem.
Böse Akteure versuchen immer, bösartige Versionen beliebter Open-Source-Pakete zu platzieren. Sie können Zugriff auf die Schlüssel für Paket-Repositorys in einem geheimen Leck erhalten; sie verwenden oft Social Engineering oder verstecken eine verschachtelte bösartige Abhängigkeit in einem scheinbar nützlichen pull request. Sogar einige Autoren selbst kommen eines Tages zu dem Schluss, dass die Welt nicht fair ist und beißen ihre Kunden mit Protestware in ihren eigenen Paketen!
Stellen Sie sich nun vor, Sie arbeiten für eine Organisation, die sowohl interne als auch Open-Source-Komponenten verwendet.
Wenn ein böswilliger Akteur den Namen solcher internen Komponenten kennt, kann er/sie es schaffen, eine Komponente mit demselben Namen im öffentlichen Repository zu veröffentlichen. Viele Paketmanager holen sich zuerst die öffentlichen Komponenten, und wenn die Version richtig gewählt ist und die Version in Ihrer deklarierten Abhängigkeit offen ist, bumm! Dieses Problem heißt Abhängigkeitsverwirrung.
Lassen Sie uns ein Beispiel zeigen. Angenommen, in unserem NPM-Projekt haben wir eine Abhängigkeit von einer privaten Komponente:
-
- NPM: paket.json
{
"Name": "mein-Projekt",
...
„Abhängigkeiten“: {...
„my-private-dep“: „>=1.0.0“,...
}
...
}
Der Angreifer kann eine höhere Hauptversion von my-private-dep (z. B. 99.0.0) erstellen und diese mit seinem eigenen Fake-Konto im öffentlichen npm-Repository veröffentlichen (der Angreifer muss nichts mit meiner Organisation zu tun haben). Der NPM-Paketmanager installiert die bösartige Abhängigkeit, oft mit verheerenden Folgen.
Die Lösung
Um diese Probleme in unserem Software-Erstellungsprozess zu vermeiden, sollten wir strenge Normen für die Deklaration von Komponentenversionen befolgen, die von der verwendeten Technologie abhängen. Wichtig ist, dass eine bestimmte Version eines Pakets, sobald sie in einem Repository veröffentlicht wurde, unveränderlich sein sollte (um zu vermeiden, dass abhängige Versionen beschädigt werden, nicht nur aus Sicherheitsgründen).
Die allgemeine Idee besteht darin, zu fixieren (Stift) Versionen, wobei immer überprüft wird, dass die korrigierten Versionen der Komponenten (einschließlich ALLER transitiven Abhängigkeiten) frei von Malware sind, und dies ist möglich dank der Sperrdateien die viele Paketmanager anbieten. Sehen wir uns an, wie Versions-Pinning bei verschiedenen Paketmanagern funktioniert. Es gibt einen heiklen Kompromiss zwischen häufige Versionsaktualisierungen zur Behebung bekannter Schwachstellen und Versionsfixierung um nicht-deterministische Builds und potenzielle Supply-Chain-Angriffe zu vermeiden.
-
- NPM:
Die Paketmanager von npm oder yarn verwenden unterschiedliche Sperrdateien (npm-shrinkwrap.json / package-lock.json bzw. yarn.lock), die feste Versionen für alle direkten und indirekten Abhängigkeiten auflisten. Die Sperrdateien sollten einer Versionskontrolle unterliegen, da andere Entwickler / Build-Knoten sonst möglicherweise mit anderen Versionen enden. Vermeiden Sie npm install, es sei denn, Sie müssen während der Entwicklung die Abhängigkeiten aktualisieren (z. B. um Sicherheitsfixes zu installieren). Verwenden Sie im Allgemeinen das deterministischere npm ci (Clean Install), damit der Paketmanager die Sperrdatei verwendet oder mit einem Fehler beendet wird, wenn keine Sperrdatei vorhanden ist oder sie nicht mit package.json übereinstimmt. Wenn die aufgelisteten Versionen auf Malware überprüft wurden, stellt die Sperrdatei sicher, dass zur Build-Zeit nichts Schlimmes passiert.Für interne Komponenten empfiehlt sich die Erstellung eines NPM-Umfang von der Organisation verwaltet werden (wie @myorg) und diesen Bereich in der Abhängigkeit verwenden (wie @myorg/my-private-dep), die nur private Sichtbarkeit haben könnte. Dies blockiert Abhängigkeitsverwirrung Angriffe, da nur Mitglieder der Organisation mit Schreibzugriff Pakete in diesem Umfang veröffentlichen können.
- NPM:
-
- Maven:
Maven / Gradle haben keine Lockfiles (siehe aber dieser StackOverflow-Artikel).Versionsbereiche werden bei Maven/Gradle nicht so häufig verwendet wie bei anderen Ökosystemen. Vermeiden Sie einfach Versionsbereiche und LATEST oder RELEASE Meta-Versionen. Indirekte Versionen sollten ebenfalls überprüft werden. Die Versionen Maven Plugin ist ein nettes Tool zur Versionskontrolle.
Bitte beachten Sie, dass Maven immer das Konzept des Organisationsbereichs hatte (der GroupId-Teil der Abhängigkeit) und Abhängigkeitsverwirrung für dieses Ökosystem überhaupt kein Problem zu sein scheint.
- Maven:
-
- Pips:
In Python gibt es verschiedene Tools zum Umgang mit Sperrdateien:- pipenv, das eine Pipfile.lock-Sperrdatei generiert.
- Poesie, das poetry.lock generiert.
- Pip einfrieren, Befehl, der eine requirements.txt generiert, die als Sperrdatei fungiert. Überprüfen Sie mit dem Operator ==, ob alle Abhängigkeiten feste Versionen verwenden. Dann verwendet pip install -r requirements.txt die festen Abhängigkeiten.
- Pips:
Denken Sie daran, dass die oben genannten Sperrdateien der Versionskontrolle unterliegen sollten und dass der gewählte Build-Befehl die Sperrdatei verwenden sollte.
Das übliche mit pip (PyPI) verwendete Paket-Repository verfügt nicht über Benennungsbereiche und ist anfällig für Abhängigkeitsverwirrungsangriffe. Vermeidung von Abhängigkeitsverwirrung im Python-Ökosystem ist nicht einfach, und einige Autoren empfehlen, ein internes Repository als Proxy für öffentliche Abhängigkeiten zu verwenden, die von PyPI abgerufen werden, aber zuerst die privaten Abhängigkeiten aus dem internen Repository zu übernehmen (-index-url sollte auf das interne Repository verweisen, nicht auf PyPI, und –extra-index- url sollte entfernt werden).
Einige echte Angriffe
Getcookies-Angriff: Der Akteur dustin87 hat dem beliebten npm-Mailparser-Paket eine indirekte Abhängigkeit zu einem bösartigen Paket mit einer RCE-Hintertür (gCOMMANDhDATAi) hinzugefügt:
JSON.stringify(req.headers).replace(/g([a-f0-9]{4})h((?:[a-f0-9]{2})+)i/gi, (o, p, v) => {})
Obwohl Mailparser veraltet war (keine Kritiker!), wurde es wöchentlich immer noch etwa 64,000 Mal heruntergeladen. Es handelte sich um einen Beinaheangriff, da der RCE nicht wirklich ausgeführt wurde.cised..
NPM veröffentlicht Dieser Beitrag mit Details zum Getcookies-Angriff.
Abhängigkeitsverwirrung:
Alex Birsan entdeckte 2021 das Problem der Abhängigkeitsverwirrung und veröffentlichte einen Beitrag mit dem Titel „Wie ich Apple, Microsoft und Dutzende anderer Unternehmen gehackt habe".
Denken Sie daran, dass für npm der Organisationsbereich wie @myorg reserviert werden sollte und interne Pakete geändert werden sollten, um den Bereich zu verwenden.
Mit pip hat das gemeinsame öffentliche Register PyPI keine Bereiche/Namespaces. Jedes private Paket könnte ein öffentliches Paket-Squat mit demselben Namen wie das interne Paket haben, das aber leer ist und bei Verwendung möglicherweise einen Fehler generiert, sodass es identifiziert werden könnte, wenn es versehentlich abgerufen wird.
Knoten-IPC:
Als der Krieg zwischen Russland und der Ukraine begann, injizierte der Paketbesitzer bei der Installation auf russischen und weißrussischen Hosts Schadcode zum Entfernen zufälliger Dateien. Die Datei ssl-geospec.js führte die folgende geografische Unterscheidung durch:
Interessanterweise verwendeten andere Pakete offene Versionen für die node-ipc-Abhängigkeit, wie das beliebte Vue.js-Framework, und seine Betreuer erhielten eine dringender Appell um die Node-IPC-Abhängigkeit auf eine sichere Version festzulegen.
Dieser Beitrag enthält weitere Details auf diese Sabotage, die einen Schritt weiter geht als andere Protestware Probleme.
Abschließende Bemerkungen
Offene Versionen sollten niemals in konsolidierten Softwareprojekten verwendet werden. Sie machen Builds nicht reproduzierbar und Angreifer können sie ausnutzen und es schaffen, über Angriffe auf die Abhängigkeitsbäume Malware einzuschleusen, wie die oben erwähnte Abhängigkeitsverwirrung.
Fehlkonfigurationen wie offene Versionen, fehlende Versionsfixierung oder interne Komponenten ohne Gültigkeitsbereich sollten vermieden werden. Zunächst gilt es, solche Probleme zu erkennen, möglicherweise sogar den Build zu blockieren, wenn sie gefunden werden, und ein standardisiertes Aktionsprotokoll zu haben.
Automatische Erkennung von Fehlern und Fehlkonfigurationen in Abhängigkeiten, Meldung verdächtiger Abhängigkeiten, die anfällig für bestimmte Supply-Chain-Angriffe sein könnten, wie Abhängigkeitsverwirrung, alle mit umsetzbaren Fix-Tools, ist eines der Hauptziele der Xygeni-Plattform.
| Um mehr zu lesen |
| Ohm M., Plate H., Sykosch A., Meier M.: „Backstabber's Knife Collection: Eine Übersicht über Angriffe auf die Lieferkette von Open-Source-Software“. DIMVA 2020. Lecture Notes in Computer Science, Bd. 12223. Springer – 2020 (Quelle der Abbildung des Abhängigkeitsangriffsbaums.) |
| @adam-npm: „Gemeldetes Schadmodul: getcookies„. npm Blog (archiviert) – 2. Mai 2018. |
| Alex Birsan: „Wie ich Apple, Microsoft und Dutzende anderer Unternehmen gehackt habe„. Medium – 9. Februar 2021. |
| Ax Sharma: „GROSSE Sabotage: Berühmtes npm-Paket löscht Dateien aus Protest gegen den Ukraine-Krieg” BleepingComputer – 17. März 2022 |





