Wichtigste Erkenntnisse
- Beim Austausch der Frachtquelle wird davon ausgegangen, dass der Ersatz denselben Kisteninhalt abdeckt, weshalb keine Änderungen an der Projektdatei erforderlich sind.
- Bei der Prüfung durch das Zuchtregister wird eine Zucht nach ihrem Inhalt beurteilt und nicht nach dem Ruf ihres Namens.
- Der Verifizierungspfad ist ein
.cargo/config.tomlÄnderung, ohne Bearbeitungen anCargo.tomloderCargo.lock. - Mit Patches versehene Kisten sind die Ausnahme, und die Entscheidung für eine solche Kiste stellt eine bewusste, offensichtliche Änderung dar.
crates.io standardmäßig zu vertrauen, ist selten eine Entscheidung, die jemand bewusst trifft. Es ist einfach die Standardeinstellung – bis sich jemand genauer damit befasst. Die nächste Frage lautet dann meist in etwa: „Was soll man stattdessen tun?“, und genau an dieser Stelle ist eine private Cargo-Registry plötzlich keine so offensichtliche Lösung mehr.
Der Begriff umfasst mindestens drei verschiedene Konfigurationen, und Cargo behandelt diese so unterschiedlich, dass die Wahl der falschen Konfiguration später zu Problemen führt. Bei einer Variante sind keine Änderungen an Ihren Projektdateien erforderlich. Eine andere Variante erfordert die Bearbeitung jedes Manifests, in dem die Abhängigkeiten deklariert sind, die Sie umleiten möchten. Die meisten Teams finden erst heraus, welche Variante welche ist, wenn sie bereits ein Stück weit mit dem Versuch fortgeschritten sind.
Eine Ausnahme sollte vor allem anderen hervorgehoben werden, da sie erst spät entdeckt wird. Die Verifizierung erfolgt ohne Änderungen an den Projektdateien. Bei gepatchten Crates ist dies nicht der Fall, und die Entscheidung für eine solche Crate ist immer eine bewusste Bearbeitung.
Was ein privates Frachtregister in der Regel bedeutet
Unter einem gemeinsamen Oberbegriff werden drei Ansätze erörtert: „Vendoring“, „Source Replacement“ (Spiegelung) und alternative Repositorien, einschließlich privater. In der Dokumentation von Cargo wird „Source Replacement“ als eigenständiger Ansatz behandelt und nicht als eine Form eines privaten Repositoriums.
| Architektur | Der Inhalt kann von crates.io abweichen. | Erfordert Änderungen an der Datei „Cargo.toml“ |
|---|---|---|
| Einreichung in das Repository | Ja, es gehört dir | Nein, fügt aber ein vendor/ Verzeichnis |
| Ersatzspiegel für die Lichtquelle | Nein, das muss dasselbe sein | Nein |
| Alternatives Register | Ja | Ja, pro Abhängigkeit |
Der Quellcode-Ersatz ist derjenige, der die Behauptung „keine Änderung des Workflows“ hervorruft, und der Grund dafür ist, dass Cargo davon ausgeht, dass der Inhalt der Crates auf beiden Seiten identisch ist.
Die Ersetzung der Frachtquelle ist für Spiegel ausgelegt. Dabei wird davon ausgegangen, dass die Ersetzung dieselbe Quelle wie das Original enthält, und es wird nicht zugelassen, dass durch die Ersetzung Kisten eingeführt werden, die das Original nicht enthält. Hier lohnt es sich, genau zu sein, da viele Anbieter in ihren Beschreibungen über das Ziel hinausschießen.
Cargo führt keine Rückverfolgung durch und gleicht die Ersetzung nicht mit crates.io ab. Was in einem echten Projekt dafür sorgt, ist Cargo.lock, da eine dort bereits gespeicherte Prüfsumme nicht mit einer Kiste übereinstimmt, deren Inhalt sich geändert hat, und der Build daher fehlschlägt, anstatt den Ersatz stillschweigend zu übernehmen.
Das klingt nach einer Einschränkung. Bei einem verifizierenden Mirror ist genau das der springende Punkt – der Ersatz soll Ihrem Build denselben Crate-Inhalt bereitstellen, den er bereits aufgelöst hat.
SecureChain funktioniert im Grunde genommen genauso. Es baut Crates aus dem Quellcode neu, überprüft sie und fügt sich nahtlos in Ihre bestehende Umgebung ein, sodass Entwickler weiterhin dieselben Cargo-Befehle ausführen können wie bisher.
Zwei Möglichkeiten, wie Sie mit Cargo Kisten umleiten können
Der Quelltext-Ersatz befindet sich in .cargo/config.toml und verändert nichts an Ihrem Projekt.
[source.crates-io]
replace-with = "securechain"
[source.securechain]
registry = "<your SecureChain registry index URL>"
Eine alternative Registrierungsstelle ist der andere Mechanismus, der von seiner Konzeption her anders funktioniert.
[registries.securechain]
index = "<your SecureChain registry index URL>"
Bei einer alternativen Registrierungsstelle muss jede Abhängigkeit diese benennen.
[dependencies]
serde = { version = "1.0", registry = "securechain" }
Das ist eine Änderung, die für jede Abhängigkeit in jedem Manifest vorgenommen werden muss, in dem eine dieser Crates deklariert ist – und genau das sind die Migrationskosten, die durch den Ersetzungsansatz vermieden werden.
Realitätscheck: Ein Anbieter, der sowohl behauptet, modifizierte Crates bereitzustellen, als auch, dass sich an Ihren Projektdateien nichts ändert, beschreibt etwas, das die standardmäßige Cargo-Quellcodeersetzung nicht unterstützt. Fragen Sie nach, welchen der beiden Mechanismen eine Integration tatsächlich nutzt – dann wird der Rest der Bewertung wesentlich einfacher.
Warum der Austausch der Quelle die Gültigkeit Ihrer Lockdatei gewährleistet
Die Frage, die sich ein umsichtiger Rust-Entwickler als Erstes stellt, lautet: Ob Cargo.lock bricht ab. Auf dem Verifizierungspfad ist dies nicht der Fall, und der Grund dafür ist von Bedeutung, da er zugleich das stärkste verfügbare Argument darstellt.
A .crate Die Datei ist ein komprimiertes Tar-Archiv der gepackten Crate-Quelldateien. Die von Cargo selbst durchgeführte Prüfsummenüberprüfung stellt sicher, dass das heruntergeladene Archiv mit der Prüfsumme übereinstimmt, die anhand der Metadaten aus dem Register und der Sperrdatei erwartet wird – mehr tut sie nicht. Es wird nichts neu kompiliert. Der eigenständige Schritt des Neukompilierens und Vergleichens erfolgt vorgelagert bei einem Dienst wie SecureChain, bevor eine Crate überhaupt über die Ersatzquelle bereitgestellt wird.
Wenn ein Rebuild vom veröffentlichten Artefakt abweicht, wird diese Abweichung zu einem Befund, der untersucht werden muss, anstatt stillschweigend übergangen zu werden. Eine Abweichung ist für sich genommen noch kein Beweis für Manipulation, da sie auch durch Besonderheiten bei der Paketierung und nicht reproduzierbare Release-Schritte entstehen kann. Entscheidend ist, dass sie zutage tritt, anstatt unter den Tisch zu fallen.
Die nützliche Eigenschaft besteht also nicht darin, dass die Überprüfung unsichtbar ist. Vielmehr kommt es darauf an, dass überprüfte Crates unverändert ankommen, während alles Unerwartete sichtbar wird, anstatt stillschweigend akzeptiert zu werden.
rm -rf ~/.cargo/registry
cargo build --locked
Wenn ein bereinigter Registrierungscache sowie --locked führt zu einem erfolgreichen Build für Ihre unveränderte Cargo.lock, wird die Kompatibilität nicht auf einer Folie, sondern in Ihrer Umgebung nachgewiesen. --locked ist das entscheidende Flag in diesem Fall, da es einen Fehler auslöst, anstatt die Sperrdatei stillschweigend zu überschreiben. Durch das vorherige Leeren des Caches wird sichergestellt, dass jede Crate erneut abgerufen und anhand der Prüfsumme überprüft wird.
Profi-Tipp: Führen Sie den Pilotversuch mit --locked und --offline in einzelnen Durchgängen. --locked beweist, dass die vorhandene Sperrdatei unverändert verwendet werden kann. --offline stellt sicher, dass der Build ohne weiteren Netzwerkzugriff abgeschlossen wird. Um zu überprüfen, ob keine Daten direkt von crates.io abgerufen wurden, sollten Sie die Egress-Protokollierung oder eine Firewall-Regel (siehe Phase 4) verwenden, anstatt sich auf --offline allein.
Was bei Vorsorgeuntersuchungen erkannt wird und was nicht
Ein privates Frachtregister macht sich angesichts zweier damit verbundener Bedrohungen bezahlt, und keine davon lässt sich durch die Überprüfung eines Namens oder einer Prüfsumme beseitigen.
Der erste Fall ist die Identitätsfälschung, bei der eine Crate unter einem Namen veröffentlicht wird, der einem beliebten Namen so ähnlich ist, dass ein Tippfehler oder ein flüchtiger Blick auf eine Cargo.toml, lässt es trotzdem installieren. Der zweite Fall ist die Übernahme: Ein Projekt, dem man seit Jahren vertraut, wechselt den Besitzer – sei es, weil ein Betreuer ausscheidet, ein Konto gehackt wurde oder eine stillschweigende Eigentumsübertragung stattfindet – und veröffentlicht dann unter einem Namen, dem Ihr Team bereits vertraut, etwas ganz anderes.
Beides hängt nicht von einer anfälligen Codezeile ab, die irgendwo in einem Abhängigkeitsbaum versteckt ist. Beides hängt vom Standardmodell von crates.io ab, bei dem jeder etwas veröffentlichen kann und ein Name mit Historie nichts darüber aussagt, wer derzeit die Kontrolle darüber hat.
Die Überprüfung, bevor ein Crate in Ihre Build-Umgebung gelangt, zielt genau darauf ab. Das Crate wird aus dem Quellcode neu kompiliert und auf bekannte Malware-Muster sowie verdächtiges Verhalten überprüft, sodass es anhand seines eigenen Inhalts beurteilt wird, anstatt allein aufgrund seines Namens als vertrauenswürdig eingestuft zu werden. Das senkt das Risiko erheblich. Es ist jedoch keine Garantie dafür, dass jedes schädliche Crate identifiziert wird, und jeder Anbieter, der ein solches Versprechen abgibt, übertreibt.
Es ist auch eine andere Garantie als die, dass in Ihrem Build niemals beliebiger Code ausgeführt wird. Die Überprüfung erfolgt, bevor das Crate in Ihren Baum gelangt. Sobald es sich in Ihrem Baum befindet, ist Ihr eigener cargo build läuft so wie immer.
| Ebene | Wer führt die Überprüfung oder die Sandbox-Prüfung durch? | Was es auffängt |
|---|---|---|
| Vor der Installation bei der Registrierungsstelle registrieren | Das Register | Identitätsbetrug, Kontoübernahme, bekannte Malware-Muster |
Dein eigenes cargo build |
Cargo führt keine Sandbox-Prüfung durch | build.rs Und proc-Makros werden weiterhin ausgeführt, es sei denn, man fügt eine externe Isolierung hinzu. |
Wie gepatchte Crates die Integration verändern
An dieser Stelle hört die Übernahme auch auf, eine reine Überprüfungsfrage zu sein. Eine Kiste, deren Eigentumsverhältnisse stillschweigend wechseln, ist kein einmaliges Erkennungsproblem. Es handelt sich um eine anhaltende Lücke in der Wartung, die durch die Überprüfung einer einzelnen Freigabe nicht geschlossen werden kann.
Die fortlaufende Pflege von Crates, die vom Upstream-Entwickler aufgegeben wurden, ist ein vom Verifizierungsvorgang getrenntes Angebot und führt zu Crates, deren Inhalt sich bewusst von dem unterscheidet, was auf crates.io veröffentlicht wurde. Ein unterschiedlicher Inhalt bedeutet unterschiedliche Prüfsummen, und die Quellcode-Ersetzung lehnt – wie vorgesehen – alles ab, was nicht übereinstimmt.
Das Patchen erfolgt also explizit pro Crate auf freiwilliger Basis. Für eine Abhängigkeit, die in Ihrem eigenen Manifest deklariert ist, reicht es aus, die alternative Registry anzugeben.
[dependencies]
abandoned-crate = { version = "1.2.4", registry = "securechain" }
Bei einer Kiste, die nur transitiv auftaucht, hat diese Deklaration keine Auswirkung, da sie nur die eine Abhängigkeit regelt, die Sie angegeben haben. Eine auf oberster Ebene [patch] „override“ ist der Mechanismus, der für den transitiven Fall entwickelt wurde.
[patch.crates-io]
abandoned-crate = { version = "1.2.4", registry = "securechain" }
Unter anderem Cargo.toml Frachtbriefe, Frachtdaten [patch] nur von der Datei im Stammverzeichnis des Arbeitsbereichs, und von dort aus gilt sie für den gesamten Abhängigkeitsgraphen. Sie kann auch in .cargo/config.toml, obwohl die Dokumentation von Cargo davon abrät, dies bei gemeinsam genutzten Dateien zu tun, da Konfigurationsdateien in der Regel nicht in die Versionsverwaltung eingecheckt werden.
In der Praxis ist eine tatsächliche Bereitstellung daher zweistufig aufgebaut.
| Bedarf | Mechanismus | Änderungen an der Projektdatei |
|---|---|---|
| Geprüfte Kisten, unverändert | Ersatz der Quelle | Keine |
| Flicken an verlassenen Kisten | Alternative Registrierungsstelle oder [patch] |
Ein kleiner expliziter Eintrag pro Kiste |
Eine Sache, die in dieser Tabelle verborgen bleibt, sollte ausdrücklich erwähnt werden. Die Entscheidung für eine modifizierte Crate kann die Quelle und die Prüfsumme verändern, die in Cargo.lock, sodass die Sperrdatei aktualisiert wird, und diese Aktualisierung sollte wie jede andere Änderung an den Abhängigkeiten festgeschrieben und überprüft werden. Bei der Verifizierung bleibt die Sperrdatei unverändert. Beim Patchen ist dies nicht der Fall.
Das ist besser als eine pauschale Aussage, denn so kann der Sicherheitskunde schon vor Vertragsunterzeichnung erkennen, welche Kosten für das Patchen anfallen. Eine kleine, gezielte Änderung für jede Kiste, für die ein Patch gewünscht wird, ist eine angemessene Forderung. Die Feststellung mitten im Pilotprojekt, dass jedes Manifest bearbeitet werden muss, ist es hingegen nicht.
Von SC Media veröffentlichte Audits von Codebasen aus der Industrie ergaben, dass 93 Prozent der untersuchten Codebasen Komponenten enthielten, bei denen in den letzten zwei Jahren keine Entwicklungsaktivitäten stattgefunden hatten. Für die tatsächlich aufgegebenen Projekte in dieser Gruppe gibt es keinen Upstream-Betreuer mehr, der eine stabile Version veröffentlichen könnte, und ein Backporting bedeutet, den Kontext von Grund auf neu aufzubauen. Den Fehler reproduzieren, einen Fix schreiben, der kein Verhalten verändert, auf das sich irgendjemand verlässt, und ihn validieren – ohne sich auf die Überprüfung oder Beurteilung durch einen aktiven Betreuer stützen zu können. TuxCare verfolgt mit SecureChain hier den Ansatz einer langfristigen Betreuung statt einer Ablösung der Upstream-Entwicklung, weshalb die beiden Funktionen unterschiedlich integriert sind.
Einführung
Vier Phasen, die so angeordnet sind, dass in jeder Phase Erkenntnisse gewonnen werden, bevor in der nächsten Phase der Umfang erweitert wird.
| Phase | Aktion | Was dies beweist |
|---|---|---|
| 1 | Quelle bei einem Dienst ersetzen, Cache leeren | Die Prüfsummen stimmen weiterhin überein |
| 2 | cargo build --offline nach Phase 1 |
Der Build wird ausschließlich mit den in Phase 1 bereits abgerufenen Komponenten abgeschlossen. |
| 3 | CI über alle Repositorys hinweg einführen | Welche Pipelines hatten eine fest codierte Quellkonfiguration? |
| 4 | Den Zugriff auf den öffentlichen crates.io-Index und die Download-Endpunkte blockieren | Was wurde in der Konfiguration stillschweigend umgangen? |
In Phase 3 laufen diese Einführungen dann tatsächlich schief. Fracht wird zusammengeführt .cargo/config.toml Dateien aus dem aktuellen Verzeichnis und den darüber liegenden Verzeichnissen, anschließend wird auf $CARGO_HOME/config.toml, wobei die tiefer liegende Datei Vorrang hat und das Stammverzeichnis den niedrigsten Rang einnimmt. Ein CI-Image kann dennoch unerwartete Konfigurationen mit sich bringen, und das Verzeichnis, aus dem „cargo“ aufgerufen wurde, entscheidet darüber, welche Dateien überhaupt in die Zusammenführung einfließen. Überprüfen Sie die tatsächliche Konfiguration auf dem Runner, anstatt nur darüber zu spekulieren.
cargo +nightly -Z unstable-options config get --show-origin source
Das gibt Auskunft über die tatsächliche Quellkonfiguration und die Herkunft der einzelnen Werte. Führen Sie den Befehl auf einem Build-Agenten statt auf einem Laptop aus, da sich die beiden in der Regel unterscheiden und nur einer davon dokumentiert ist.
Anmerkung: Dafür wird ein nächtlicher Cargo-Lauf benötigt mit -Z unstable-options, daher sollte man dies nicht einfach so in eine stabile CI-Pipeline integrieren.
Profi-Tipp: Führen Sie Phase 4 eine Woche lang in der Staging-Umgebung durch, bevor Sie die Produktion umstellen. Blockieren Sie den Sparse-Index unter index.crates.io und die Downloads unter static.crates.io. Falls irgendwo in der Flotte noch das Git-Protokoll verwendet wird, muss auch das crates.io-Index-Repository auf github.com blockiert werden. Die Pipelines, bei denen es zu Fehlern kommt, decken in der Regel Pfade auf, von denen niemand wusste, dass sie noch direkt von crates.io beziehen – und diese Liste ist als Dokumentation wertvoller als als Postmortem.
Wo eine private Registrierungsstelle allein nicht ausreicht
Verifiziertes Mirroring, also der Austausch der Quelle, löst das Problem „Ist das dasselbe Paket?“. Die Crate, die in Ihrem Build landet, ist diejenige, die Ihre Lockfile bereits aufgelöst hat. Es sagt Ihnen jedoch nicht, ob die Crate von vornherein vertrauenswürdig war – und genau das wird durch einen ähnlichen Namen oder eine Crate-Übernahme ausgenutzt.
SecureChain für Rust deckt beide Aspekte ab. Jedes Crate wird aus dem Quellcode neu kompiliert und auf Integrität überprüft; anschließend wird es auf böswilliges und verdächtiges Verhalten untersucht, bevor es Sie erreicht. So werden durch Tippfehler missbrauchte und durch Übernahme manipulierte Veröffentlichungen anhand ihres Inhalts beurteilt, anstatt ihnen allein aufgrund ihres Namens und ihrer Historie zu vertrauen.
Außerdem werden auch die bereits in Ihrem Stack vorhandenen Komponenten weiterhin gepatcht, nachdem die Betreuer ihre Arbeit eingestellt haben. Sobald ein Crate das Ende seiner Lebensdauer erreicht hat, sorgt der „Endless Lifecycle Support“ dafür, dass weiterhin Backports bereitgestellt werden, damit eine aufgegebene Abhängigkeit nicht unbemerkt zu einer ungepatchten wird.
Erfahren Sie, wie viel eine verifizierte und gepatchte Abdeckung für Ihren tatsächlichen Abhängigkeitsbaum kostet, und fordern Sie ein Angebot an.
FAQ
Was ist ein privates Frachtregister?
Ein privates Cargo-Registry ist ein internes oder von einem Anbieter betriebenes alternatives Registry für Rust-Crates. Es unterscheidet sich sowohl vom Einbinden von Crates in Ihr Repository als auch vom Spiegeln von crates.io mithilfe der Cargo-Quellersetzung. Diese beiden Methoden steuern auf unterschiedliche Weise, woher die Crates stammen, doch nur ein alternatives Registry fungiert im eigentlichen Sinne von Cargo als privates Registry.
Führt das Spiegeln von crates.io durch das Ersetzen der Quelle dazu, dass die Datei „Cargo.lock“ beschädigt wird?
Nicht, wenn die Ersatzquelle verifizierte, unveränderte Crates bereitstellt, da der Inhalt identisch ist und die gespeicherten Prüfsummen weiterhin mit Ihrer bestehenden Sperrdatei übereinstimmen. Crates mit verändertem Inhalt können über die Quellcode-Ersetzung überhaupt nicht übertragen werden.
Wie konfiguriere ich die Quelltextersetzung in Cargo?
Füge ein [source.crates-io] Block mit replace-with Wenn Sie auf eine namentlich genannte Quelle verweisen, definieren Sie diese Quelle mit ihrer Registry-Index-URL, und zwar sowohl in .cargo/config.toml. Keine Änderungen an Cargo.toml oder Cargo.lock werden benötigt.
Erkennt die Quellcode-Ersetzung durch Typosquatting betroffene oder missbrauchte Crates?
Die Quellersetzung allein reicht nicht aus. Ihre Aufgabe besteht darin, Cargo auf eine gleichwertige Quelle umzuleiten, während der Inhalt der Crate unverändert bleibt. Das Erkennen eines Namens, der dem ursprünglichen ähnelt, oder einer Crate, die den Besitzer gewechselt hat, ist eine Überprüfungsfunktion, die beim ersten Neuaufbau einer Crate und erneut bei der Veröffentlichung neuer Versionen ausgeführt wird – es handelt sich dabei nicht um eine Eigenschaft des Umleitungsmechanismus.
Wie funktionieren „Patched Crates“ mit Cargo?
Gepatchte Crates unterscheiden sich inhaltlich von den von crates.io veröffentlichten Crates und können daher nicht durch eine Quellcodeersetzung bereitgestellt werden. Eine direkte Abhängigkeit kann auf ein alternatives Repository verweisen, während eine Top-Level- [patch] „override“ ersetzt die geänderte Kopie im gesamten Abhängigkeitsgraphen, einschließlich transitiver Verwendungen. In beiden Fällen wird die Änderung in der Sperrdatei protokolliert.
Wie kann ich die Kompatibilitätsangabe selbst überprüfen?
Löschen ~/.cargo/registry, dann führen Sie Folgendes aus cargo build --locked. Ein erfolgreicher Build mit geleertem Cache anhand Ihrer unveränderten Sperrdatei zeigt, dass die Ersatzquelle mit dem gesperrten Abhängigkeitssatz kompatibel ist und dass die heruntergeladenen Pakete den von Cargo erwarteten Prüfsummen entsprechen. Die Ausführung von cargo build --offline Anschließend wird bestätigt, dass der Build ohne weiteren Netzwerkzugriff abgeschlossen wird; die Herkunft der bereits zwischengespeicherten Daten wird jedoch nicht bestätigt. Verwenden Sie hierfür daher die Egress-Protokollierung oder eine Firewall-Regel.



