DevOps

Sicherheitsmaßnahmen vor Supply Chain Angriffen

Im Softwarebereich kommt es immer häufiger zu Angriffen auf die Lieferkette von Unternehmen. Diese Attacken verbreiten sich oft automatisiert und können innerhalb kürzester Zeit eine Vielzahl von Systemen kompromittieren.

Daher ist es entscheidend, im gesamten Softwareprozess die Risiken externer Abhängigkeiten sorgfältig einzuschätzen und kontinuierlich zu überwachen. Ein Teil dieser Aufgabe lässt sich automatisieren, wie wir an einem Beispiel zeigen.

Der NPM Wurm "Shai Hulud"

Am 24. November erschütterte ein schwerwiegender Supply-Chain-Angriff erneut die Open-Source-Gemeinschaft. Mehrere SDKs und weitere Softwarepakete eines Herstellers wurden kompromittiert und mit einem selbstreplizierenden Schadprogramm infiziert, das sich unbemerkt in der Entwicklerumgebung ausbreiten konnte.

Über manipulierte Veröffentlichungen im npm-Ökosystem breitete sich der Angriff automatisch weiter. Die kompromittierten Pakete enthielten ein bösartiges "preinstall"-Skript, das beim Installieren automatisch ausgeführt wurde und so eine erhebliche Gefahr für Entwickler und Unternehmen darstellte.

Wer ein infiziertes Paket installiert hat, verbreitet den Wurm potenziell weiter durch GitHub Tokens. Um einen schnell Überblick zu bekommen, ob ein Softwareprojekt davon betroffen ist, kann gezielt nach speziellen Dateien gesucht werden.

find . -name "setup_bun.js"
find . -name "truffleSecrets.json"

grep -R "shai" ~/.npm/_logs
grep -R "preinstall" ~/.npm/_logs

Falls es Anzeichen gibt, dass das Projekt betroffen ist müssen alle GitHub-Tokens, npm-Tokens, SSH-Schlüssel, API-Schlüssel und Umgebungsvariablen-Geheimnisse erneuert werden, die möglicherweise offengelegt wurden.

Außerdem sollten die gecachten Dependencies entfernt werden:

rm -rf node_modules
npm cache clean --force
pnpm cache delete

Sicherheitsprüfung von Dependencies

Diese und ähnliche Angriffe mit Malware über Updates können durch Hinweise im Code in NPM-Paketen erkannt werden, wie beispielsweise durch Base64-codierte Daten oder Installationsskripte.

Bestimmte Funktionen sollten daher besonders kritisch geprüft werden. Um Entwickler bei der Analyse ihrer Projekte zu unterstützen, haben wir eine Liste relevanter Suchbegriffe zusammengestellt.

Keywords wie postinstall, preinstall, install, prepare und prepublish

Codeausführung mit exec(, execSync(, spawn(, fork(, "child_process", Buffer.from(, eval(, Function(, require(

# Find base64
grep -RnE -C 3 -A 3 "[A-Za-z0-9+/]{20,}={1,2}" node_modules

# Search install scripts
grep -RInE -A 5 '"(preinstall|install|postinstall|prepare)"' node_modules
grep -RInE -A 5 '"(prepare|prepublish|preprepare|postprepare)"' node_modules
grep -RInE -A 5 '"(prepack|postpack)"' node_modules
grep -RInE -A 5 '"(prepublishOnly|postpublish)"' node_modules
grep -RInE -A 5 '"(prerestart|restart|postrestart)"' node_modules
grep -RInE -A 5 '"(prestop|stop|poststop)"' node_modules
grep -RInE -A 5 '"(pretest|test|posttest)"' node_modules

Quelle: https://docs.npmjs.com/cli/v11/using-npm/scripts

Um die eigenen Softwareabhängigkeiten zuverlässig zu prüfen, empfiehlt es sich, den aktuellen Stand der statischen Analyse festzuhalten und Änderungen bei Updates automatisiert mit diff zu vergleichen. Auf diese Weise lassen sich unerwartete Modifikationen erkennen und das Einschleusen versteckter Malware in ein Softwareprojekt verhindern.

ignore-Scripts nutzen

Außerdem ist es möglich bei npm install mit dem Parameter --ignore-scripts, die Ausführung von install-Scripten zu verhindern. Dies kann auch Global per Default festgelegt werden mit: npm config -g set ignore-scripts true. Doch dies gilt nur für Scripte, die in package.json festgelegt wurden. npm start führt weiterhin Code aus.

Note that commands explicitly intended to run a particular script, such as npm start, npm stop, npm restart, npm test, and npm run will still run their intended script if ignore-scripts is set, but they will not run any pre- or post-scripts.
https://docs.npmjs.com/cli/v11/using-npm/config#ignore-scripts

Feste Versionsnummern nutzen

Bei einer Installation über npm, beispielsweise mit npm install lodash --save, wird die Versionsnummer einer Abhängigkeit nicht fixiert, sondern automatisch die jeweils neueste kompatible Version installiert. Aus Gründen der Stabilität und Nachvollziehbarkeit sollten Bibliotheken jedoch auf eine feste Version gesetzt werden.

!! NICHT FIXIERT !!
"dependencies": {
  "lodash": "^4.17.21"
}

>> FIXIERT <<
"dependencies": {
  "lodash": "4.17.21"
}

Unsere Kunden können sich jederzeit an unseren Support wenden, wenn sie Unterstützung bei der Erstellung entsprechender Tests für ihr Softwareprojekt benötigen.