Über Rust, Speichersicherheit und Open-Source-Infrastruktur

Von Tara Tarakiyee

In STF

Die Speichersicherheit in kritischen Infrastrukturen ist ein komplexes Thema mit mehreren Lösungsansätzen. Der Sovereign Tech Fund unterstützt zahlreiche Initiativen, und Technologist Tara Tarakiyee reflektiert über den langen Weg, der noch vor uns liegt.

Am frühen Morgen des 19. Juli 2001 begann ein Computerwurm (eine Art von Malware), Computer zu infizieren, auf denen der IIS-Webserver von Microsoft lief. Innerhalb von 14 Stunden infizierte er mehr als 359.000 Computer weltweit. Diese vom Center for Applied Internet Data Analysis (CAIDA) erstellte Animation zeigt die Verbreitung und Reichweite des Wurms, der schließlich Code Red genannt wurde. Ryan Permeh und Marc Maiffret von eEye Digital Security gaben ihm diesen Namen, weil Mountain Dew Code Red das koffeinhaltige Getränk ihrer Wahl war und „das Einzige, was uns wach hielt, während wir diesen Schadcode auseinander nahmen“.

Auch wenn Code Red langfristig keinen großen Schaden anrichten konnte (von den Nebenwirkungen des übermäßigen Koffeinkonsums einmal abgesehen), war es das erste Beispiel eines groß angelegten Angriffs auf die Internet-Infrastruktur und ein Vorbote vieler weitreichender Sicherheitslücken, die folgten. Code Red war auch ein Frühwarnzeichen und unterstrich die Notwendigkeit, die Software zu sichern, auf die wir uns alle verlassen. Code Red nutzte eine Software-Schwachstelle in IIS aus, die als Pufferüberlauf bezeichnet wird, eine Art von Speichersicherheitsfehler.

🐛 Was ist ein Speichersicherheitsfehler?

Die meisten Programme müssen Daten in den Speicher eines Computers schreiben und von dort abrufen, um ordnungsgemäß zu funktionieren. Dazu muss das Programm auch wissen, wo es im Speicher schreiben kann und bereits Daten gespeichert hat, damit diese später wieder abgerufen werden können.

Wenn etwas schiefgeht, z. B. wenn ein Programm versucht, Daten an eine Stelle zu schreiben, an die es nicht darf, kann dies zu unbeabsichtigten Datenlecks, Datenverlust oder Abstürzen führen. Böswillige Akteur*innen können diese Schwachstellen auch ausnutzen, um eines der oben genannten Probleme zu erzwingen oder die volle Kontrolle über das Programm und im schlimmsten Fall über den Computer zu übernehmen, auf dem es läuft.

Code Red war nicht das erste Beispiel für einen Speichersicherheitsfehler. Viele Softwareprojekte und Unternehmen schätzen, dass 65–70 % aller in ihren Codebasen gefundenen Fehler mit der Speichersicherheit zusammenhängen.

Der Sovereign Tech Fund (STF) hat es sich zur Aufgabe gemacht, in die Sicherheit kritischer Open-Source-Infrastrukturen zu investieren. Es sollte daher nicht überraschen, dass wir mehrere Initiativen unterstützen, die sich mit dem Thema Speichersicherheit befassen, wenn man bedenkt, wie weit verbreitet diese Sicherheitslücken sind. In diesem Blogbeitrag gehen wir darauf ein, wie komplex das Thema Speichersicherheit ist, welche Lösungsansätze zur Behebung von Sicherheitslücken es gibt und wie unsere Investitionen dazu beitragen, sowie auf einige der Grenzen, auf die wir stoßen.

Rust: Die neue(re) Infrastruktur-Sprache

Um die Verbreitung von Anfälligkeiten bei der Speichersicherheit zu verhindern, besteht der beste Weg darin, dafür zu sorgen, dass sie erst gar nicht entstehen. Das ist seit einiger Zeit möglich, dank der Entwicklung neuerer Programmiersprachen wie Rust, Go, C#, Java, Swift, Python und JavaScript. Diese Sprachen können verhindern, dass Programmierende Schwachstellen einführen, oder den Speicher so verwalten, dass solche Schwachstellen unwahrscheinlich werden. Wir werden nicht auf die allgemeinen Vorteile von speichersicheren Sprachen eingehen, da es zu diesem Thema eine Menge Literatur gibt. Stattdessen werden wir speziell auf Rust eingehen und darauf, wie es sich auf kritische Infrastrukturen anwenden lässt, die im Mittelpunkt der Mission der STF stehen.

Ältere Programmiersprachen wie C, C++ und Assembler garantieren bedauerlicherweise keine Speichersicherheit, da ein Großteil der kritischen Infrastruktur, auf die wir alle angewiesen sind, in diesen Sprachen geschrieben ist. Es ist erwähnenswert, dass C++ zwar Funktionen enthält, die es schrittweise sicherer machen als C, aber immer noch nicht mit der Sicherheit von Rust vergleichbar sind. Das liegt daran, dass die meisten speichersicheren Sprachen oft mit einem gewissen Aufwand verbunden sind, wodurch sie weniger effizient als C und C++ arbeiten. Bei einigen Anwendungen kann dies aufgrund der zusätzlichen Funktionen dieser Sprachen (einschließlich der Speichersicherheit) ein fairer Kompromiss sein, aber im Falle von Infrastrukturen und anderen Bereichen, in denen Leistung an erster Stelle steht, kann dies unerwünscht sein.

An dieser Stelle kommt Rust ins Spiel. Rust kombiniert die Speichersicherheit der neueren Programmiersprachen mit einer vergleichbaren Leistung wie in C oder C++ geschriebener Code. Außerdem ist es widerstandsfähiger gegenüber anderen Arten von Schwachstellen, wie Integer-Überlauf, Validierungsschwachstellen und Datenrennen. Dies hat dazu beigetragen, Rust zu einer der beliebtesten Sprachen des Jahres 2023 zu machen. Der STF hat in mehrere Initiativen investiert, die die Entwicklung und Implementierung kritischer Infrastruktur-Software in Rust beinhalten. Einige mögen sich fragen, warum man überhaupt noch kritische Infrastruktur unterstützt, die in Sprachen mit manuell verwaltetem Speicher (sprich: nicht speichersichere Sprachen) geschrieben wurde.

Zu sagen, dass Rust „vor Schwachstellen in der Speichersicherheit schützt“, ist vielleicht zu stark vereinfacht. Rust erzwingt Programmierpraktiken, die dazu beitragen, dass Schwachstellen in der Speichersicherheit nicht in den Quellcode eingebracht werden. Diese strenge Durchsetzung bedeutet zum Beispiel, dass der Rust-Compiler das Kompilieren von möglicherweise unsicherem Code unterbindet. Das hat zur Folge, dass Rust selbst für die erfahrensten Programmierenden eine steilere Lernkurve aufweist. Es bedeutet auch, dass das Umschreiben von Code von C nach Rust alles andere als eine triviale Übung ist und eine erhebliche Überarbeitung der Logik oder Architektur der Software erfordert.

Auch bei der statischen Analyse von Code gibt es Einschränkungen, da dem Code Analysator der Kontext fehlt, den Programmierende möglicherweise haben. So gibt es zum Beispiel gültige Anwendungsfälle für direkte Interaktion mit dem Computerspeicher in einer Weise, die andernfalls potenziell unsicher wäre. Rust trägt dem Rechnung, indem es eine „unsafe“ Deklaration enthält, mit der Programmierende dem Rust-Compiler mitteilen können, dass sie wissentlich manuell verwaltete Speicheranweisungen einfügen, die der Compiler normalerweise ablehnen würde, und dass die Programmierenden ihre Gründe dafür haben, dies zu tun. Der Vorteil dieses Ansatzes ist, dass die „unsafe“-Deklaration den Code als unsicher kennzeichnet und zu einer zusätzlichen Überprüfung einlädt, um zukünftige Probleme zu vermeiden.

Aus den vorgenannten Gründen und aufgrund der Tatsache, dass es so viel Legacy-Code gibt, der in Sprachen mit manuell verwaltetem Speicher geschrieben wurde, werden C und C++ in absehbarer Zeit nicht verschwinden - schon gar nicht ohne erhebliche Investitionen. Da wir keine Schwachstellen in unserer bestehenden kritischen Infrastruktur wollen, müssen wir zusätzliche Strategien einsetzen, um das Risiko kritischer Infrastrukturen, die in Sprachen mit manuell verwaltetem Speicher geschrieben sind, zu minimieren. Dazu gehören Entwickler*innen-Tools wie Fuzzer und Sanitizer, die Schwachstellen finden können, die während der Entwicklung eingeführt werden, und Investitionen in allgemeine Strategien zur Bekämpfung von Schwachstellen in der Softwareentwicklung.

Worin STF investiert (bis jetzt)

Wir sind dankbar, dass wir in diesem Bereich mit äußerst beeindruckenden und effektiven Projekten zusammenarbeiten, um zu mehr Speichersicherheit beizutragen, und möchten deshalb eine kurze Einführung in alle Projekte geben. Da sich in wenigen Sätzen nicht allzu viel sagen lässt, schau dir die Projekte gerne genauer an, wenn sie dein Interesse geweckt haben. Wir haben auch Einblicke von einigen dieser Projekte in diesen Blogbeitrag aufgenommen, wofür wir sehr dankbar sind.

DNS

Das Domain Name System (DNS) ist das Telefonbuch des Internets. Wo immer du oder ein von dir verwendetes Programm, einen Domainnamen aufruft, ist DNS der Standard, mit dem dieser von Menschen lesbare Name in eine maschinenlesbare IP-Adresse übersetzt wird. Das bedeutet, dass du deine Lieblingswebseite besuchen kannst, ohne dir 12 Zahlen (oder sogar 32 hexadezimale Zeichen) für jede Seite merken zu müssen. Es handelt sich um einen wichtigen Internetstandard und einen entscheidenden Teil unserer Infrastruktur.

Der STF investiert in die „domain“ Rust-Bibliothek von NLNet Labs, die darauf abzielt, einen umfassenden Satz von Bausteinen für die Interaktion mit DNS in Anwendungen zu schaffen. Da heutzutage viele Anwendungen mit dem Internet und damit auch mit DNS interagieren müssen, ist es sehr wichtig, dass diese Schnittstellen modern und sicher sind.

Ein weiteres Projekt, in das der STF investiert, ist das Hickory DNS Projekt. Hickory DNS ist eine Rust-Implementierung des DNS-Standards, die aus einem Client, einem Server und einem Resolver besteht. Ein DNS-Resolver ist die Software, die die Übersetzung eines Domainnamens in eine IP-Adresse übernimmt. Hickory DNS unterstützt auch die neuesten DNS-Sicherheitsstandards.

Verschlüsselung

Ein weiterer wichtiger Teil der Internet-Infrastruktur ist Transport Layer Security (TLS), der Internetstandard, mit dem ein Großteil der Online-Kommunikation verschlüsselt wird. Er schützt unsere Privatsphäre und Datensicherheit in allen Bereichen, von E-Mail und Instant Messaging bis hin zu Konferenzen und Internet-Telefonie, und vor allem im Internet. STF investiert in rustls, eine moderne, speichersichere Rust-Implementierung des TLS-Protokolls. Rustls ist ein Beweis für das Versprechen von Rust und ist bereits auf dem Weg, die am weitesten verbreitete TLS-Implementierung OpenSSL zu übertreffen – und das bei gleichzeitiger Gewährleistung der Speichersicherheit.

OpenPGP ist ein weiterer wichtiger Verschlüsselungsstandard. Er ist nicht so weit verbreitet wie TLS und dient einem anderen Zweck, ist aber besonders wichtig für die Überprüfung der Authentizität, Herkunft und Integrität von Daten, die online ausgetauscht werden, wie Software oder E-Mails. Um die Entwicklung des OpenPGP-Standards voranzutreiben, ist es wichtig, dass es mehrere interoperable Implementierungen gibt, die eine Vielzahl von Anwendungsfällen abdecken. Der STF hat deshalb in drei solcher Implementierungen von OpenPGP in speichersicheren Sprachen investiert: Sequoia PGP, gopenpgp und OpenPGP.js.

Jede dieser Implementierungen wird in kritischen Infrastrukturen eingesetzt und dient unterschiedlichen Communitys mit Verschlüsselungs- und Verifizierungstechnologie. Da sie alle den OpenPGP-Standard implementieren und zu ihm beitragen, können sie als Gruppe Implementierungsdetails und Daten austauschen und gemeinsam Interoperabilitätsprobleme lösen, die den Standard besser und sicherer machen.

Multimedia-Kodierung/Dekodierung

Die Technologie der Multimedia-Kodierung und -Dekodierung beruht in hohem Maße auf Speicheroperationen und ist sehr anfällig für Speichersicherheitsfehler. Video und Audio haben sich in den letzten zwei Jahrzehnten im Internet stark verbreitet, und diese Verbreitung bedeutet, dass Multimedia-Kodierer und -Dekodierer überall eingesetzt werden, was sie zu einer kritischen Infrastruktur macht. Der STF hat in rav1d investiert, eine quelloffene AV1-Decoder-Bibliothek, die in Rust geschrieben wurde und sich auf Effizienz und Speichersicherheit konzentriert. AV1 ist ein Videokodierungsformat, das aufgrund seiner hohen Effizienz und Komprimierung bei gleichbleibender Videoqualität sehr begehrt ist. Wir haben auch in das weit verbreitete GStreamer Multimedia-Framework investiert und unterstützen dessen Bemühungen, kritische Komponenten seiner Bibliothek von C auf Rust umzustellen, nämlich das Real-Time Transport Protocol, das die Grundlage seiner Streaming- und Videokonferenzprotokolle bildet.

NTP

Ein Internetprotokoll, das für das Funktionieren unserer digitalen Infrastruktur von entscheidender Bedeutung ist, aber wenig Beachtung findet, ist das Network Time Protocol. Wie der Name schon sagt, hilft das NTP dabei, allen Arten von Geräten über das Netzwerk eine genaue und zuverlässige Zeit zu liefern. Wir unterstützen Pendulum, ein Projekt, das sowohl NTP als auch das Precision Time Protocol in Rust implementiert.

Speichersicherheit von Anfang an ist ein entscheidender Vorteil für unsere kritischen Systeme. Menschen neigen dazu, all die Zeit und Energie, die wir für Schwachstellen, Abhilfemaßnahmen, Schadensbegrenzung und Sicherheitsverletzungen aufwenden, als naturgegeben zu betrachten, als etwas, mit dem wir einfach umgehen müssen. Das ist nicht der Fall, und wir müssen es auch nicht. Wir haben die Chance, eine ganze Kategorie von Fehlern und damit eine große Anzahl von Schwachstellen zu beseitigen.

— Erik Jonkers, Direktor für Open Source bei Tweede golf

Entwickler*innen-Tooling

Linux ist eines der beliebtesten Betriebssysteme der Welt, und Debian ist eine der beliebtesten Linux-Distributionen. Eine bestimmte Bibliothek, auf die sich viele Linux-Distributionen wie Debian verlassen, ist die GNU coreutils Bibliothek. Sie stellt viele der grundlegenden Funktionen bereit, ohne die das Betriebssystem nicht funktionieren kann. Wir arbeiten mit den Entwickler*innen von Debian zusammen, um einige dieser grundlegenden und wichtigen Programme in Rust umzuschreiben.

Wo wir gerade von Werkzeugen für Programmierer*innen sprechen: Wir arbeiten mit Trail of Bits zusammen, um einen wesentlichen Beitrag zum Python Package Index zu leisten. Ein großer Teil dieser Arbeit konzentriert sich auf das PyCA Cryptography-Paket, eine weit verbreitete Software-Bibliothek, deren interne Entwicklung zu einem großen Teil in Rust stattfindet. Das Ziel dieser Bemühungen ist es, mehr Menschen zu ermöglichen, sicher in speichersicheren Sprachen zu programmieren. Als Teil dieser Zusammenarbeit wird Trail of Bits eine einheitliche Sigstore-Packaging-Client-Richtlinie für die Ökosysteme Python, Rust und Ruby entwickeln.

Speicherunsicherheit ist eine der Hauptursachen für angreifbare Schwachstellen in Open-Source-Codebasen sowie eine der größten Quellen für technische Schulden und Wartungsrisiken für das Open-Source-Ökosystem als Ganzes. Trail of Bits ist stolz darauf, mit dem Sovereign Tech Fund in seiner Mission zusammenzuarbeiten, die Säulen des Open-Source-Ökosystems zu stärken und zu sichern.

— William Woodruff, Technischer Direktor bei Trail of Bits

Einige Anmerkungen: Auch wenn es nicht direkt um die Übertragung von Implementierungen mit manuell verwaltetem Speicher in speichersichere Sprachen geht, möchten wir doch einige andere Bemühungen erwähnen, die wir unterstützen und die indirekt die „anderen“ Strategien anwenden, die wir im letzten Abschnitt erwähnt haben. Zum Beispiel tragen wir zum Rust-Developer-Tooling bei, indem wir das Rusty SBOM Projekt bei der Erweiterung der Software-Bill-of-Materials Unterstützung im Rust-Ökosystem vorantreiben. Andere speichersichere Sprachen, für die wir Entwickler*innen-Tools unterstützen, sind Ruby und Javascript, um Entwicklern*innen die Verwendung dieser speichersicheren Sprachen zu erleichtern. Mit dem Yocto-Projekt unterstützen wir die Verbesserung von Build-Tools, Fuzzing und Entwicklungspraktiken, die erforderlich sind, um das Risiko der Verwendung speicherunsicherer Sprachen zu minimieren.

Fazit

Es sollte inzwischen klar sein, dass die Speichersicherheit weder ein Allheilmittel noch ein Sturm im Wasserglas ist. Ein guter Vergleich ist vielleicht die Ausrottung der Pocken. Was einst eine sehr verbreitete und tödliche Krankheit war, gibt es heute nicht mehr. Dafür bedurfte es konzentrierter, langwieriger und koordinierter Anstrengungen vieler Menschen. Natürlich gibt es noch andere Krankheiten, aber jede*r würden zustimmen, dass der Aufwand es wert war – allein schon wegen all der durch die Verhinderung zukünftige Ausbrüche geretteten Leben.

Mit der Speichersicherheit können wir einen Weg zur Beseitigung einer ganzen Gruppe von Schwachstellen wie Code Red erkennen. Dies wird dazu beitragen, unsere kritischen Infrastrukturen zu sichern und das Risiko zu minimieren, dass in Zukunft großflächige Schwachstellen auftreten, die unserer digitalen Infrastruktur und damit unserer Wirtschaft, unseren Institutionen und unserer Gesellschaft unermesslichen Schaden zufügen könnten, da immer mehr davon online geschieht. Um dieses Ziel zu erreichen, müssen viele Menschen ihren Teil dazu beitragen. Deshalb möchten wir uns eine Minute Zeit nehmen, um einige der laufenden Bemühungen zu würdigen, auf die wir in dieser Hinsicht gestoßen sind.

  • Die US-Behörde für Cybersicherheit und Infrastruktursicherheit hat die Speichersicherheit als eine der Säulen ihrer „Secure by Default“-Strategie identifiziert und Leitlinien für speichersichere Roadmaps herausgegeben.
  • Wir möchten auch der Internet Security Research Group Anerkennung dafür aussprechen, dass sie sich mit ihrem Projekt Prossimo frühzeitig für dieses Thema eingesetzt hat.
  • Consumer Reports veröffentlichte ebenfalls einen umfassenden Bericht zur Speichersicherheit mit konkreten Empfehlungen an Industrie und Staat.
  • Die OpenSSF der Linux Foundation hat eine spezielle Interessengruppe zur Förderung der Speichersicherheit gegründet.
  • Zu guter Letzt möchten wir Alex Gaynor für seinen informativen Blogbeitrag zu diesem Thema danken.

Diese Liste ist natürlich nicht vollständig, und wir möchten uns abschließend bei der Rust Community für ihre harte Arbeit in den letzten Jahren bedanken und für den guten Ruf, dass sie für Anfänger*innen freundlich und offen ist. Wir haben im vergangenen Jahr beim Scouting von Technologien und der Recherche für diesen Blogbeitrag viele Beispiele dafür aus erster Hand gesehen und möchten diesen Trend in den Communitys loben.


Mehr Artikel

Alle Artikel