In diesem Dokument werden Anwendungsabhängigkeiten und Best Practices für die Verwaltung von Abhängigkeiten beschrieben, einschließlich der Überwachung von Sicherheitslücken, der Überprüfung von Artefakten, der Reduzierung des Abhängigkeitsumfangs und der Unterstützung reproduzierbarer Builds.
Eine Softwareabhängigkeit ist ein Softwareteil, der für die Funktion Ihrer Anwendung erforderlich ist, z. B. eine Softwarebibliothek oder ein Plug-in. Abhängigkeiten können aufgelöst werden, wenn Sie Code kompilieren, Software erstellen, ausführen, herunterladen oder installieren.
Abhängigkeiten können sowohl von Ihnen erstellte Komponenten als auch proprietäre Drittanbietersoftware und Open-Source-Software umfassen. Die Art und Weise, wie Sie Abhängigkeiten verwalten, kann sich auf die Sicherheit und Zuverlässigkeit Ihrer Anwendungen auswirken.
Die genauen Schritte zur Umsetzung der Best Practices können je nach Artefakttyp und den verwendeten Tools variieren, die allgemeinen Grundsätze gelten jedoch weiterhin.
Direkte und transitive Abhängigkeiten
Ihre Anwendungen können sowohl direkte als auch transitive Abhängigkeiten enthalten:
- Direkte Abhängigkeiten
- Softwarekomponenten, auf die eine Anwendung direkt verweist.
- Transitive Abhängigkeiten
- Softwarekomponenten, die für die Funktion der direkten Abhängigkeiten einer Anwendung erforderlich sind. Jede Abhängigkeit kann eigene direkte und indirekte Abhängigkeiten haben. So entsteht ein rekursiver Baum von transitiven Abhängigkeiten, die sich alle auf die Anwendung auswirken.
Verschiedene Programmiersprachen bieten unterschiedliche Einblicke in Abhängigkeiten und ihre Beziehungen. Außerdem verwenden einige Sprachen Paketmanager, um den Abhängigkeitsbaum beim Installieren oder Bereitstellen eines Pakets aufzulösen.
Im Node.js-Ökosystem verwenden die Paketmanager npm und yarn Lock-Dateien, um Abhängigkeitsversionen für das Erstellen eines Moduls und die Abhängigkeitsversionen zu identifizieren, die ein Paketmanager für eine bestimmte Installation des Moduls herunterlädt. In anderen Sprach-Ökosystemen wie Java ist die Unterstützung für die Abhängigkeitsanalyse eingeschränkter. Außerdem müssen Build-Systeme bestimmte Abhängigkeitsmanager verwenden, um Abhängigkeiten systematisch zu verwalten.
Sehen Sie sich als Beispiel das npm-Modul glob
Version 8.0.2 an. Direkte Abhängigkeiten für npm-Module werden in der Datei package.json
deklariert. Im package.json-Dokument für glob werden im Abschnitt dependencies
die direkten Abhängigkeiten für das veröffentlichte Paket aufgeführt.
Im Abschnitt devDepdencies
sind Abhängigkeiten für die lokale Entwicklung und das Testen durch Maintainer und Mitwirkende von glob
aufgeführt.
Auf der npm-Website werden auf der glob-Seite die direkten Abhängigkeiten und Entwicklungsabhängigkeiten aufgeführt. Es wird jedoch nicht angegeben, ob diese Module auch eigene Abhängigkeiten haben.
Weitere Informationen zu den Abhängigkeiten von
glob
finden Sie auf der Open Source Insights-Website. Die Abhängigkeitsliste für glob enthält sowohl direkte als auch indirekte (transitive) Abhängigkeiten.Eine transitive Abhängigkeit kann im Abhängigkeitsbaum mehrere Ebenen tief sein. Beispiel:
glob
8.0.2 hat eine direkte Abhängigkeit vonminimatch
5.0.1.minimatch
5.0.1 hat eine direkte Abhängigkeit vonbrace-expression
2.0.1.brace-expression
2.0.1 hat eine direkte Abhängigkeit vonbalanced-match
1.0.2.
Ohne Einblick in indirekte Abhängigkeiten ist es sehr schwierig, Sicherheitslücken und andere Probleme zu erkennen und darauf zu reagieren, die von einer Komponente stammen, auf die Ihr Code nicht direkt verweist.
Wenn Sie das Paket glob
installieren, löst npm den gesamten Abhängigkeitsbaum auf und speichert die Liste der heruntergeladenen Versionen in der Datei package.lock.json, damit Sie einen Datensatz aller Abhängigkeiten haben. Bei nachfolgenden Installationen in derselben Umgebung werden dieselben Versionen abgerufen.
Tools für Abhängigkeitsinformationen
Mit den folgenden Tools können Sie Ihre Open-Source-Abhängigkeiten nachvollziehen und den Sicherheitsstatus Ihrer Projekte bewerten. Diese Tools liefern Informationen zu allen Paketformaten.
- Sicherheitsinformationen in der Google Cloud -Konsole
- Google Cloud bietet Sicherheitsinformationen für Ihre Artefakte in Cloud Build, Cloud Run und GKE, einschließlich Informationen zu Sicherheitslücken, Abhängigkeiten, Software Bill of Materials (SBOM) und Build-Herkunft. Andere Google Cloud Dienste bieten ebenfalls Funktionen, die Ihren Sicherheitsstatus im gesamten Lebenszyklus der Softwareentwicklung verbessern. Weitere Informationen
- Open-Source-Tools
Es sind eine Reihe von Open-Source-Tools verfügbar, darunter:
Open Source Insights: Eine Website, die Informationen zu bekannten direkten und indirekten Abhängigkeiten, bekannten Sicherheitslücken und Lizenzinformationen für Open-Source-Software bietet. Das Open Source Insights-Projekt stellt diese Daten auch als Google Cloud Dataset zur Verfügung. Mit BigQuery können Sie die Daten untersuchen und analysieren.
Open-Source-Sicherheitslückendatenbank: Eine durchsuchbare Sicherheitslückendatenbank, in der Sicherheitslücken aus anderen Datenbanken an einem Ort zusammengefasst werden.
Scorecards: Ein automatisiertes Tool, mit dem Sie riskante Praktiken in der Software-Lieferkette in Ihren GitHub-Projekten identifizieren können. Es werden Prüfungen für Repositories durchgeführt und jeder Prüfung wird eine Punktzahl zwischen 0 und 10 zugewiesen. Anschließend können Sie die Werte verwenden, um die Sicherheitslage Ihres Projekts zu bewerten.
Allstar: Eine GitHub-App, die GitHub-Organisationen oder ‑Repositories kontinuierlich auf die Einhaltung der konfigurierten Richtlinien überwacht. Sie können beispielsweise eine Richtlinie auf Ihre GitHub-Organisation anwenden, die nach Mitarbeitern außerhalb der Organisation sucht, die Administrator- oder Push-Zugriff haben.
Methoden zum Einbeziehen von Abhängigkeiten
Es gibt mehrere gängige Methoden, um Abhängigkeiten in Ihre Anwendung einzubinden:
- Direkt aus öffentlichen Quellen installieren
- Open-Source-Abhängigkeiten direkt aus öffentlichen Repositories wie Docker Hub, npm, PyPI oder Maven Central installieren. Dieser Ansatz ist praktisch, da Sie Ihre externen Abhängigkeiten nicht verwalten müssen. Da Sie diese externen Abhängigkeiten jedoch nicht kontrollieren, ist Ihre Softwarelieferkette anfälliger für Open-Source-Lieferkettenangriffe.
- Kopien von Abhängigkeiten in Ihrem Quell-Repository speichern
- Dieser Ansatz wird auch als Vendoring bezeichnet. Anstatt eine externe Abhängigkeit während der Builds aus einem öffentlichen Repository zu installieren, laden Sie sie herunter und kopieren sie in den Quellbaum Ihres Projekts. Sie haben mehr Kontrolle über die verwendeten Anbieterabhängigkeiten, aber es gibt auch einige Nachteile:
- Anbieterbasierte Abhängigkeiten erhöhen die Größe Ihres Quellcode-Repositorys und führen zu mehr Änderungen.
- Sie müssen dieselben Abhängigkeiten in jede separate Anwendung einbinden. Wenn Ihr Quell-Repository oder Build-Prozess keine wiederverwendbaren Quellmodule unterstützt, müssen Sie möglicherweise mehrere Kopien Ihrer Abhängigkeiten verwalten.
- Das Aktualisieren von Anbieteranbieter-Abhängigkeiten kann schwieriger sein.
- Abhängigkeiten in einer privaten Registry speichern
Eine private Registry wie Artifact Registry bietet den Komfort der Installation aus einem öffentlichen Repository sowie die Kontrolle über Ihre Abhängigkeiten. Mit Artifact Registry haben Sie folgende Möglichkeiten:
- Zentralisieren Sie Ihre Build-Artefakte und Abhängigkeiten für alle Ihre Anwendungen.
- Konfigurieren Sie Ihre Docker- und Sprachpaketclients so, dass sie mit privaten Repositories in Artifact Registry genauso interagieren wie mit öffentlichen Repositories.
Sie haben mehr Kontrolle über Ihre Abhängigkeiten in privaten Repositories:
- Den Zugriff auf die einzelnen Repositories mit Identity and Access Management einschränken
- Verwenden Sie Remote-Repositories, um Abhängigkeiten aus öffentlichen Upstream-Quellen zu cachen und auf Sicherheitslücken zu scannen (private Vorschau).
- Verwenden Sie virtuelle Repositories, um Remote- und private Repositories hinter einem einzelnen Endpunkt zu gruppieren. Legen Sie für jedes Repository eine Priorität fest, um die Suchreihenfolge beim Herunterladen oder Installieren eines Artefakts zu steuern (Private Preview).
Verwenden Sie Artifact Registry mit anderen Google Cloud -Diensten, darunter Cloud Build, Cloud Run und Google Kubernetes Engine. Automatisches Scannen auf Sicherheitslücken im gesamten Softwareentwicklungszyklus, Generieren von Build-Herkunft, Steuern von Bereitstellungen und Anzeigen von Statistiken zu Ihrer Sicherheitslage.
Verwenden Sie nach Möglichkeit eine private Registry für Ihre Abhängigkeiten. Wenn Sie keine private Registry verwenden können, sollten Sie Ihre Abhängigkeiten einbinden, damit Sie die Kontrolle über die Inhalte in Ihrer Softwarelieferkette haben.
Angepinnte Version
Beim Anpinnen von Versionen wird eine Anwendungsabhängigkeit auf eine bestimmte Version oder einen bestimmten Versionsbereich beschränkt. Im Idealfall fixieren Sie eine einzelne Version einer Abhängigkeit.
Wenn Sie die Version einer Abhängigkeit anpinnen, können Sie sicherstellen, dass Ihre Anwendungs-Builds reproduzierbar sind. Das bedeutet aber auch, dass Ihre Builds keine Updates für die Abhängigkeit enthalten, einschließlich Sicherheitskorrekturen, Fehlerkorrekturen oder Verbesserungen.
Sie können dieses Problem mit automatisierten Tools zur Abhängigkeitsverwaltung beheben, die Abhängigkeiten in Ihren Quell-Repositories auf neue Releases überwachen. Diese Tools aktualisieren Ihre Anforderungsdateien, um Abhängigkeiten nach Bedarf zu aktualisieren. Oft enthalten sie auch Informationen zum Changelog oder zusätzliche Details.
Die Versionsfixierung gilt nur für direkte Abhängigkeiten, nicht für transitive Abhängigkeiten. Wenn Sie beispielsweise die Version des Pakets my-library
fixieren, wird die Version von my-library
eingeschränkt, aber nicht die Versionen der Software, von der my-library
abhängig ist. Sie können den Abhängigkeitsbaum für ein Paket in einigen Sprachen mit einer Sperrdatei einschränken.
Signatur- und Hash-Überprüfung
Es gibt verschiedene Methoden, mit denen Sie die Authentizität eines Artefakts überprüfen können, das Sie als Abhängigkeit verwenden.
- Hash-Überprüfung
Ein Hash ist ein generierter Wert für eine Datei, der als eindeutige Kennung dient. Sie können den Hash eines Artefakts mit dem vom Anbieter des Artefakts berechneten Hashwert vergleichen, um die Integrität der Datei zu bestätigen. Mit der Hash-Überprüfung können Sie erkennen, ob Abhängigkeiten durch einen Man-in-the-Middle-Angriff oder durch eine Kompromittierung des Artefakt-Repositorys ersetzt, manipuliert oder beschädigt wurden.
Wenn Sie die Hash-Überprüfung verwenden, müssen Sie darauf vertrauen, dass der Hash, den Sie vom Artefakt-Repository erhalten, nicht manipuliert wurde.
- Signaturüberprüfung
Die Signaturüberprüfung bietet zusätzliche Sicherheit für den Bestätigungsprozess. Artefakte können vom Artefakt-Repository, den Maintainern der Software oder von beiden signiert werden.
Dienste wie sigstore bieten Maintainern die Möglichkeit, Softwareartefakte zu signieren, und Nutzern, diese Signaturen zu überprüfen.
Mit der Binärautorisierung kann geprüft werden, ob Container-Images, die in Google Cloud -Laufzeitumgebungen bereitgestellt werden, mit Attestierungen für verschiedene Kriterien signiert sind.
Sperrdateien und kompilierte Abhängigkeiten
Sperrdateien sind vollständig aufgelöste Anforderungsdateien, in denen genau angegeben wird, welche Version jeder Abhängigkeit für eine Anwendung installiert werden soll. Sperrdateien werden in der Regel automatisch von Installationstools erstellt. Sie kombinieren das Fixieren von Versionen und die Überprüfung von Signaturen oder Hashes mit einem vollständigen Abhängigkeitsbaum für Ihre Anwendung.
Installations-Tools erstellen Abhängigkeitsbäume, indem sie alle nachgelagerten transitiven Abhängigkeiten Ihrer Abhängigkeiten der obersten Ebene vollständig auflösen und den Abhängigkeitsbaum dann in Ihre Sperrdatei aufnehmen. Daher können nur diese Abhängigkeiten installiert werden, was Builds reproduzierbarer und konsistenter macht.
Private und öffentliche Abhängigkeiten mischen
Moderne cloudnative Anwendungen sind häufig sowohl auf Open-Source-Code und Code von Drittanbietern als auch auf interne Bibliotheken mit geschlossenem Quellcode angewiesen. Mit Artifact Registry können Sie Ihre Geschäftslogik für mehrere Anwendungen freigeben und dieselben Tools zum Installieren externer und interner Bibliotheken verwenden.
Wenn Sie jedoch private und öffentliche Abhängigkeiten mischen, ist Ihre Softwarelieferkette anfälliger für einen Dependency Confusion-Angriff. Wenn Sie Projekte mit demselben Namen wie Ihr internes Projekt in Open-Source-Repositories veröffentlichen, können Angreifer möglicherweise falsch konfigurierte Installationsprogramme nutzen, um ihren schädlichen Code anstelle Ihrer internen Abhängigkeit zu installieren.
Um einen Angriff durch Verwechslung von Abhängigkeiten zu vermeiden, können Sie eine Reihe von Maßnahmen ergreifen:
- Sie können die Signatur oder die Hashes Ihrer Abhängigkeiten überprüfen, indem Sie sie in eine Sperrdatei aufnehmen.
- Trennen Sie die Installation von Drittanbieterabhängigkeiten und internen Abhängigkeiten in zwei separate Schritte auf.
- Spiegeln Sie die benötigten Drittanbieterabhängigkeiten explizit in Ihr privates Repository, entweder manuell oder mit einem Pull-Through-Proxy. Remote-Repositories von Artifact Registry sind Pull-Through-Proxys für öffentliche Upstream-Repositories.
- Mit virtuellen Repositories können Sie Remote- und Standard-Artifact Registry-Repositories hinter einem einzigen Endpunkt zusammenfassen. Sie können Prioritäten für Upstream-Repositories konfigurieren, damit Ihre privaten Artefaktversionen immer Vorrang vor öffentlichen Artefakten mit demselben Namen haben.
- Verwenden Sie vertrauenswürdige Quellen für öffentliche Pakete und Basis-Images.
- Mit Assured Open Source Software können Sie auf beliebte Java- und Python-Images zugreifen, die von Google getestet und verifiziert wurden.
- Verwenden Sie von Google bereitgestellte Basis-Images oder eine sichere Image-Pipeline, um eigene Basis-Images zu generieren.
Nicht verwendete Abhängigkeiten entfernen
Wenn sich Ihre Anforderungen ändern und Ihre Anwendung weiterentwickelt wird, ändern oder beenden Sie möglicherweise die Verwendung einiger Ihrer Abhängigkeiten. Wenn Sie weiterhin ungenutzte Abhängigkeiten mit Ihrer Anwendung installieren, vergrößert sich der Umfang Ihrer Abhängigkeiten und das Risiko, dass Sie durch eine Sicherheitslücke in diesen Abhängigkeiten kompromittiert werden.
Sobald Ihre Anwendung lokal funktioniert, ist es üblich, alle Abhängigkeiten, die Sie während der Entwicklung installiert haben, in die Datei „requirements“ für Ihre Anwendung zu kopieren. Anschließend stellen Sie die Anwendung mit allen diesen Abhängigkeiten bereit. Dieser Ansatz trägt dazu bei, dass die bereitgestellte Anwendung funktioniert, führt aber wahrscheinlich auch zu Abhängigkeiten, die Sie in der Produktion nicht benötigen.
Seien Sie vorsichtig, wenn Sie Ihrer Anwendung neue Abhängigkeiten hinzufügen. Jede dieser Optionen birgt das Risiko, dass Sie mehr Code einbinden, über den Sie nicht die vollständige Kontrolle haben. Integrieren Sie als Teil Ihrer regulären Linting- und Testpipeline Tools, mit denen Ihre Anforderungsdateien geprüft werden, um festzustellen, ob Sie Ihre Abhängigkeiten tatsächlich verwenden oder importieren.
Für einige Sprachen gibt es Tools, mit denen Sie Ihre Abhängigkeiten verwalten können. Sie können beispielsweise das Maven Dependency-Plug-in verwenden, um Java-Abhängigkeiten zu analysieren und zu verwalten.
Scannen auf Sicherheitslücken
Wenn Sie schnell auf Sicherheitslücken in Ihren Abhängigkeiten reagieren, können Sie Ihre Softwarelieferkette schützen.
Mit dem Scannen auf Sicherheitslücken können Sie automatisch und konsistent prüfen, ob Ihre Abhängigkeiten Sicherheitslücken in Ihre Anwendung einführen. Tools zum Scannen auf Sicherheitslücken verwenden Sperrdateien, um genau zu ermitteln, von welchen Artefakten Sie abhängig sind. Sie benachrichtigen Sie, wenn neue Sicherheitslücken auftreten, manchmal sogar mit vorgeschlagenen Upgradepfaden.
Mit Artifact Analysis werden beispielsweise Sicherheitslücken in Betriebssystempaketen in Container-Images erkannt. Images können beim Hochladen in Artifact Registry gescannt werden. Die Daten werden bis zu 30 Tage nach dem Hochladen des Images kontinuierlich auf neue Sicherheitslücken geprüft.
Sie können auch On-Demand-Scanning verwenden, um Container-Images lokal auf Betriebssystem-, Go- und Java-Sicherheitslücken zu scannen. So können Sie Sicherheitslücken frühzeitig erkennen und beheben, bevor Sie sie in Artifact Registry speichern.
Nächste Schritte
- Informationen zu den Komponenten der Sicherheit der Softwarelieferkette und dazu, wieGoogle Cloud -Dienste Sie beim Schutz Ihrer Software unterstützen können.
- Weitere Informationen zu Artifact Registry
- Informationen zu Artifact Analysis und Scantypen.