Blog

Rust ist zum fünften Mal die meistgeliebte Programmiersprache. Ist sie unser neuer Sicherheitsretter?

Matias Madou, Ph.D.
Veröffentlicht Jun 18, 2020

In den letzten Jahren scheint es, dass Software-Ingenieure auf der ganzen Welt nicht genug von Rust bekommen können. Diese relativ neue, von Mozilla entwickelte Systemprogrammiersprache hat die Herzen der Stack Overflow-Gemeinschaft erobert - und als eine Kohorte, die keine Dummheiten duldet, ist es an der Zeit, dass wir alle aufhorchen, wenn sie etwas fünf Jahre hintereinander zur"beliebtesten Programmiersprache" wählt.

Die Programmiersprache Rust enthält bekannte und funktionale Elemente aus häufig verwendeten Sprachen und arbeitet nach einer anderen Philosophie, die Komplexität beseitigt und gleichzeitig Leistung und Sicherheit einführt. Es ist eine Lernkurve, und viele Entwickler haben nicht die Möglichkeit, viel damit zu spielen - nur 5,1 % der auf Stack Overflow befragten Personen nutzten sie häufig. Abgesehen davon lässt sich jedoch nicht leugnen, dass es sich um eine aufregende Sprache handelt, die im Vergleich zu ihren Vorgängern wie C und C++ über viel mehr Sicherheitspotenzial verfügt. Die Masseneinführung wird einige Veränderungen erfordern, sowohl in Bezug auf das Verhalten als auch auf die Technologie... aber im Moment erregt sie noch die Aufmerksamkeit von Entwicklern auf theoretischer Ebene.  

... aber Moment, wir müssen noch eine weitere Sache beleuchten: Es ist wichtig zu erwähnen, dass Rust eine Programmiersprache ist, die der Speichersicherheit und der Ausmerzung von Sicherheitsfehlern, die mit häufigen Speicherverwaltungsproblemen verbunden sind, Priorität einräumt. Diese sind eine große Sache (und verursachen zweifellos mehr als nur ein paar AppSec-Teams Migräne), aber sie sind nicht die einzigen Herausforderungen, denen wir bei der sicheren Programmierung gegenüberstehen.

Was genau wird durch Rust verhindert? Und wo gibt es noch Lücken in der Sicherheitslandschaft? Lassen Sie uns das neueste Programmier-Einhorn auspacken:

Die neue Grenze der modernen, speichersicheren Systemprogrammierung

Das Forschungs- und Entwicklungsteam von Mozilla hat an einigen unglaublichen Projekten gearbeitet, und die Investition in die Rust-Programmierung als Open-Source-Vorreiter ist keine Ausnahme. Das Einführungsvideo gibt einen Einblick in das Ethos des Teams, wobei das Hauptthema klar herausgestellt wird: Der derzeitige Ansatz zur Softwaresicherheit ist mangelhaft, und Rust wurde entwickelt, um einen Großteil dieses Problems zu lösen.

Das scheint zu simpel zu sein, zumal wir jeden Tag mit enormen Datenschutzverletzungen konfrontiert werden - wie bei dem jüngsten schrecklichen Vorfall bei EasyJet. Millionen von Datensätzen werden häufig kompromittiert, fast immer durch eine Schwachstelle in einer Webanwendung, eine falsche Sicherheitskonfiguration oder einen Phishing-Angriff, und Sprachen wie C++ gibt es schon seit Jahrzehnten. Die Zeit hat jedoch nicht ausgereicht, um sie so weit zu beherrschen, dass die besten Praktiken für eine sichere Programmierung umgesetzt werden können. Warum sollte das bei Rust anders sein? Neue Sprachen sind schon früher auf den Markt gekommen, und es ist nicht so, dass sie einen Weg gefunden hätten, allgemeine Schwachstellen auszumerzen oder sicherzustellen, dass jeder geschriebene Code beim Kompilieren auf magische Weise perfekt ist.

So einfach das Konzept auch sein mag, manchmal sind es die einfachen Antworten, die komplexe Fragen überwinden. Rust ist im wahrsten Sinne des Wortes eine Revolution in der speichersicheren Systemprogrammierung, die in vielerlei Hinsicht hält, was sie verspricht... und sie rettet sicherlich den Speck von Entwicklern, die anfällig dafür sind, Fehler einzuführen, die große Probleme verursachen können, wenn sie unentdeckt bleiben. Java, C, C++ und sogar neuere Sprachen wie Kotlin und Golang sind für den sicherheitsunbewussten Entwickler ziemlich unversöhnlich. Bei diesen gibt es keine eingebauten Warnungen, keine besonderen Anzeichen dafür, dass die großartige Funktion, die gerade kompiliert wurde, einen Sicherheits-Gremlin unter der Haube versteckt hat.

Also, lassen Sie uns tiefer graben:

Was macht Rust so sicher?

Typischerweise hat ein Entwickler das primäre Ziel, Funktionen zu erstellen und sicherzustellen, dass sie funktional und benutzerfreundlich sind - vielleicht sogar Quellen des Stolzes, die er gerne in seinem Lebenslauf vorzeigen würde. Es ist völlig normal, dass ein Entwickler eine großartige Software erstellt, sie ausliefert und sich dem nächsten großen Projekt zuwendet. An diesem Punkt suchen Sicherheitsteams nach Schwachstellen, und wenn diese gefunden werden, kann es sein, dass die "fertige" Anwendung an das Team zurückgeschickt wird, um ein Hotfix zu erhalten. Das Problem kann einfach sein, oder es kann völlig außerhalb des vernünftigen Rahmens für einen Entwickler liegen, um es zu beheben.

Das Problem ist, dass die Sicherheitslücken oberflächlich betrachtet überhaupt nicht offensichtlich waren, und wenn Scannen, Testen und manuelle Codeüberprüfung sie nicht aufspüren, dann kann ein Angreifer dieses kleine Zeitfenster potenziell nutzen, um den Fehler auszunutzen.

Rust versucht zu verhindern, dass viele Schwachstellen überhaupt erst in den Code gelangen: Es wird einfach nicht kompiliert, wenn es Syntaxfehler oder andere Speichersicherheitsfehler gibt, die während des gesamten SDLCs Produktionsprobleme verursachen. Dies ist speichersichere Programmierung per Design, die sicherstellt, dass es keinen Zugriff auf ungültigen Speicher gibt (egal wie die Software ausgeführt wird). Und angesichts der Tatsache, dass 70 % aller Sicherheitsprobleme auf Probleme in der Speicherverwaltung zurückzuführen sind, ist dies eine große Leistung.

Rost wird angezeigt und verhindert:

  • Pufferüberlauf
  • Verwendung nach freier
  • Doppelfrei
  • Null-Zeiger-Dereferenz
  • Verwendung von nicht initialisiertem Speicher

Wenn wir einen Rust-Codeschnipsel mit C++ vergleichen, wird deutlich, dass der eine standardmäßig sicher ist. Sehen Sie sich dieses Beispiel eines Pufferüberlauf-Bugs an:

#include <iostream></iostream>
#include <string.h></string.h>
int main( void ) {
char a[3] = "12";
char b[4]= "123";
strcpy(a, b); // buffer overflow as len of b is greater than a
std::cout << a << "; " << b << std::endl;
}

Vs.

pub fn main() {
let mut a: [char; 2] = [1, 2];
let b: [char; 3] = [1, 2, 3];
a.copy_from_slice(&b);
}
Vergleich eines Rust-Codeausschnittes

Rust gibt eine Sicherheitswarnung aus und gerät beim Erreichen der copy_from_slice-Funktion zur Laufzeit in Panik, um einen Pufferüberlauf zu verhindern, aber nicht zur Kompilierzeit.

In diesem Sinne ist es eine der "Start Left"-Sprachen. Sie wird Fehler hervorheben und den Entwicklern die richtige Art und Weise beibringen, Code zu schreiben, um die Einführung von speicherbezogenen Sicherheitsfehlern zu vermeiden, so dass die Einhaltung von Fristen davon abhängt, dass der Programmierer aufpasst, Korrekturen vornimmt und dem Lieferpfad treu bleibt.

Der Ansatz dieser Sprache scheint einfach zu sein, aber es wäre eine unglaubliche Leistung gewesen, sie mit dieser mächtigen Logik zum Laufen zu bringen, und sie macht es auch. Aus der Sicherheitsperspektive ist Rust ein riesiger Sprung nach vorn... wenn nur mehr Menschen es verwenden würden. Unternehmen wie Dropbox leisten Pionierarbeit bei der Verwendung von Rust in großen Unternehmen, und das ist großartig zu sehen. Aber es gibt noch mehr zu bedenken, bevor wir zu dem Schluss kommen, dass die Akzeptanz das einzige ist, was uns von einer sichereren Zukunft abhält.

Die Rust-Abrechnung.

Es gibt ein paar kleine (okay, große) Probleme, nämlich, dass die Programmierung in Rust mehr Flexibilität bietet, um Fehler einzuführen, als es vielleicht den Anschein hat. Es wird die wichtigen OWASP Top 10 Schwachstellen nicht beheben, die weiterhin zu Sicherheitslücken, Verzögerungen und einer allgemeinen Kultur unsicherer Programmiertechniken führen. Es gibt auch so etwas wie eine Engel- und Teufel-Dynamik, oder, wie es allgemein bekannt ist: Sicheres Rust vs. Unsicheres Rust.

Wie in der offiziellen Dokumentation erklärt wird, ist Safe Rust die "wahre" Form von Rust, und Unsafe Rust enthält Funktionen, die als "definitiv nicht sicher" gelten, obwohl sie manchmal notwendig sind - zum Beispiel, wenn eine Integration mit etwas in einer anderen Sprache erforderlich ist. Aber auch bei Unsafe Rust ist die Liste der zusätzlichen Funktionalitäten noch begrenzt. In Unsafe Rust ist es möglich, innerhalb von unsicheren Blöcken Folgendes zu tun:

  • Dereferenzierung von Rohzeigern
  • Aufrufen unsicherer Funktionen (einschließlich C-Funktionen, Compiler-Intrinsics und dem Raw Allocator)
  • Unsichere Traits implementieren
  • Statik mutieren
  • Zugriffsfelder von Unions.

Auch im sogenannten "unsicheren" Modus funktioniert eine der Superkräfte der Rust-Programmierung: der "Borrow Checker". Er verhindert im Allgemeinen Speicherprobleme, Kollisionen bei parallelen Berechnungen und viele andere Fehler durch statische Code-Analyse, und diese Analyse wird in einem unsicheren Block immer noch Prüfungen vornehmen - es erfordert nur viel mehr Arbeit, unsichere Konstrukte zu schreiben, ohne dass der Compiler in bestimmten Situationen mit einer Anleitung eingreift.

Für die meisten erfahrenen Entwickler scheint dies kein großes Problem zu sein - schließlich sind wir dafür bekannt, zu tüfteln, um das Beste aus unseren Anwendungen herauszuholen und einige coolere Funktionen zu eröffnen -, aber es öffnet möglicherweise ein schwarzes Loch, das zu ernsthaften Fehlkonfigurationen und Sicherheitslücken führen kann: undefiniertes Verhalten. Die Programmierung in Rust (selbst bei unsicherer Verwendung) schließt die Möglichkeiten von Sicherheitslücken im Vergleich zu C oder C++ ziemlich gut ein, aber der Aufruf von undefiniertem Verhalten kann ein Risiko darstellen.

Ist dies das Ende des Vertrauens in die entwicklergeführte sichere Kodierung?

Erinnern Sie sich, als ich vorhin sagte, dass Rust Komponenten von bekannten Sprachen enthält? Eine der größten Sicherheitsschwachstellen von Rust ist, dass es Komponenten bekannter Sprachen enthält - nämlich C.

Rust ist immer noch eine "sichere Programmiersprache", aber auch hier ist die Einführung eines Benutzers der Punkt, an dem die Dinge aus dem Ruder laufen können. Der Entwickler kann es immer noch so anpassen, dass es ohne Fehlermeldung läuft (ein attraktiver Vorschlag, da dies mehr Fähigkeiten freischaltet), und im Wesentlichen können Entwickler sogar im sicheren Zustand so "unsicher" sein, wie sie wollen, weil sie eine Schicht von Anleitung und Schutz haben, bevor die Dinge wirklich birnenförmig werden können.

Und beide oben genannten Szenarien werden gefährlicher, je tiefer wir eintauchen, da die Ergebnisse von Rust denen von Scanning-Tools ähneln - so wie es kein SAST/DAST/RAST/IAST-Tool der Schweizer Armee gibt, das jede Schwachstelle, jeden Angriffsvektor und jedes Problem aufspürt, gibt es auch Rust nicht. Selbst mit Rust können einige Schwachstellen immer noch recht einfach eingeführt werden.

Das Risiko undefinierten Verhaltens bei der Verwendung von unsicherem Rust hat das Potenzial, Integer-Überlauf-Probleme auszulösen, während im Allgemeinen sogar die sicheren Konfigurationen menschliche Fehler bei Sicherheitsfehlkonfigurationen, Geschäftslogik oder der Verwendung von Komponenten mit bekannten Schwachstellen nicht verhindern können. Diese Probleme stellen immer noch eine sehr reale Bedrohung dar, wenn sie nicht gepatcht werden, und in einer "vermeintlich sicheren" Umgebung wie echtem Rust kann dies sogar zu einem selbstgefälligen Verhalten führen, wenn ein Programmierer glaubt, dass alle wichtigen Probleme trotzdem erkannt werden.

Ich habe festgestellt, dass Rust einem Mentor in der Programmierung nicht unähnlich ist - ein erfahrener Ingenieur, der sich die Zeit genommen hat, sich mit einem weniger erfahrenen Programmierer zusammenzusetzen, seine Arbeit zu überprüfen und ihm potenzielle Fehler zu zeigen, ihn auf Effizienzsteigerungen hinzuweisen und in einigen Fällen sicherzustellen, dass die Arbeit nicht kompiliert wird, bevor sie nicht richtig ist. Für Rust-Programmierer ist es jedoch weitaus besser, die Theorie zu lernen und sich selbst zu bewährten Verfahren zu verpflichten, denn der Mentor könnte die Schürze abnehmen, und Sie wollen nicht hängen gelassen werden.

Sind Sie bereit, gängige Rust-Schwachstellen zu finden und zu beheben, und zwar sofort? Spielen Sie die Herausforderung.
Ressource anzeigen
Ressource anzeigen

Rust übernimmt bekannte und funktionale Elemente aus gängigen Sprachen und arbeitet nach einer anderen Philosophie, die Komplexität beseitigt und gleichzeitig Leistung und Sicherheit einführt.

Interessiert an mehr?

Matias Madou, Ph.D., ist Sicherheitsexperte, Forscher, CTO und Mitbegründer von Secure Code Warrior. Matias promovierte an der Universität Gent im Bereich Anwendungssicherheit und konzentrierte sich dabei auf statische Analyselösungen. Später wechselte er zu Fortify in den USA, wo er erkannte, dass es nicht ausreicht, nur Codeprobleme zu erkennen, ohne den Entwicklern beim Schreiben von sicherem Code zu helfen. Dies inspirierte ihn dazu, Produkte zu entwickeln, die Entwickler unterstützen, den Aufwand für die Sicherheit verringern und die Erwartungen der Kunden übertreffen. Wenn er nicht an seinem Schreibtisch im Team Awesome sitzt, steht er gerne auf der Bühne und hält Vorträge auf Konferenzen wie der RSA Conference, BlackHat und DefCon.

Secure Code Warrior ist für Ihr Unternehmen da, um Sie dabei zu unterstützen, Ihren Code über den gesamten Lebenszyklus der Softwareentwicklung hinweg zu sichern und eine Kultur zu schaffen, in der Cybersicherheit an erster Stelle steht. Ganz gleich, ob Sie AppSec-Manager, Entwickler, CISO oder ein anderer Sicherheitsverantwortlicher sind, wir können Ihrem Unternehmen helfen, die mit unsicherem Code verbundenen Risiken zu reduzieren.

Demo buchen
Weitergeben:
Autor
Matias Madou, Ph.D.
Veröffentlicht Jun 18, 2020

Matias Madou, Ph.D., ist Sicherheitsexperte, Forscher, CTO und Mitbegründer von Secure Code Warrior. Matias promovierte an der Universität Gent im Bereich Anwendungssicherheit und konzentrierte sich dabei auf statische Analyselösungen. Später wechselte er zu Fortify in den USA, wo er erkannte, dass es nicht ausreicht, nur Codeprobleme zu erkennen, ohne den Entwicklern beim Schreiben von sicherem Code zu helfen. Dies inspirierte ihn dazu, Produkte zu entwickeln, die Entwickler unterstützen, den Aufwand für die Sicherheit verringern und die Erwartungen der Kunden übertreffen. Wenn er nicht an seinem Schreibtisch im Team Awesome sitzt, steht er gerne auf der Bühne und hält Vorträge auf Konferenzen wie der RSA Conference, BlackHat und DefCon.

Matias ist ein Forscher und Entwickler mit mehr als 15 Jahren praktischer Erfahrung im Bereich der Softwaresicherheit. Er hat Lösungen für Unternehmen wie Fortify Software und sein eigenes Unternehmen Sensei Security entwickelt. Im Laufe seiner Karriere hat Matias mehrere Forschungsprojekte zur Anwendungssicherheit geleitet, die zu kommerziellen Produkten geführt haben, und kann auf über 10 Patente verweisen. Wenn er nicht am Schreibtisch sitzt, ist Matias als Ausbilder für fortgeschrittene Anwendungssicherheitstrainings courses tätig und hält regelmäßig Vorträge auf globalen Konferenzen wie RSA Conference, Black Hat, DefCon, BSIMM, OWASP AppSec und BruCon.

Matias hat einen Doktortitel in Computertechnik von der Universität Gent, wo er die Sicherheit von Anwendungen durch Programmverschleierung untersuchte, um die innere Funktionsweise einer Anwendung zu verbergen.

Weitergeben:

In den letzten Jahren scheint es, dass Software-Ingenieure auf der ganzen Welt nicht genug von Rust bekommen können. Diese relativ neue, von Mozilla entwickelte Systemprogrammiersprache hat die Herzen der Stack Overflow-Gemeinschaft erobert - und als eine Kohorte, die keine Dummheiten duldet, ist es an der Zeit, dass wir alle aufhorchen, wenn sie etwas fünf Jahre hintereinander zur"beliebtesten Programmiersprache" wählt.

Die Programmiersprache Rust enthält bekannte und funktionale Elemente aus häufig verwendeten Sprachen und arbeitet nach einer anderen Philosophie, die Komplexität beseitigt und gleichzeitig Leistung und Sicherheit einführt. Es ist eine Lernkurve, und viele Entwickler haben nicht die Möglichkeit, viel damit zu spielen - nur 5,1 % der auf Stack Overflow befragten Personen nutzten sie häufig. Abgesehen davon lässt sich jedoch nicht leugnen, dass es sich um eine aufregende Sprache handelt, die im Vergleich zu ihren Vorgängern wie C und C++ über viel mehr Sicherheitspotenzial verfügt. Die Masseneinführung wird einige Veränderungen erfordern, sowohl in Bezug auf das Verhalten als auch auf die Technologie... aber im Moment erregt sie noch die Aufmerksamkeit von Entwicklern auf theoretischer Ebene.  

... aber Moment, wir müssen noch eine weitere Sache beleuchten: Es ist wichtig zu erwähnen, dass Rust eine Programmiersprache ist, die der Speichersicherheit und der Ausmerzung von Sicherheitsfehlern, die mit häufigen Speicherverwaltungsproblemen verbunden sind, Priorität einräumt. Diese sind eine große Sache (und verursachen zweifellos mehr als nur ein paar AppSec-Teams Migräne), aber sie sind nicht die einzigen Herausforderungen, denen wir bei der sicheren Programmierung gegenüberstehen.

Was genau wird durch Rust verhindert? Und wo gibt es noch Lücken in der Sicherheitslandschaft? Lassen Sie uns das neueste Programmier-Einhorn auspacken:

Die neue Grenze der modernen, speichersicheren Systemprogrammierung

Das Forschungs- und Entwicklungsteam von Mozilla hat an einigen unglaublichen Projekten gearbeitet, und die Investition in die Rust-Programmierung als Open-Source-Vorreiter ist keine Ausnahme. Das Einführungsvideo gibt einen Einblick in das Ethos des Teams, wobei das Hauptthema klar herausgestellt wird: Der derzeitige Ansatz zur Softwaresicherheit ist mangelhaft, und Rust wurde entwickelt, um einen Großteil dieses Problems zu lösen.

Das scheint zu simpel zu sein, zumal wir jeden Tag mit enormen Datenschutzverletzungen konfrontiert werden - wie bei dem jüngsten schrecklichen Vorfall bei EasyJet. Millionen von Datensätzen werden häufig kompromittiert, fast immer durch eine Schwachstelle in einer Webanwendung, eine falsche Sicherheitskonfiguration oder einen Phishing-Angriff, und Sprachen wie C++ gibt es schon seit Jahrzehnten. Die Zeit hat jedoch nicht ausgereicht, um sie so weit zu beherrschen, dass die besten Praktiken für eine sichere Programmierung umgesetzt werden können. Warum sollte das bei Rust anders sein? Neue Sprachen sind schon früher auf den Markt gekommen, und es ist nicht so, dass sie einen Weg gefunden hätten, allgemeine Schwachstellen auszumerzen oder sicherzustellen, dass jeder geschriebene Code beim Kompilieren auf magische Weise perfekt ist.

So einfach das Konzept auch sein mag, manchmal sind es die einfachen Antworten, die komplexe Fragen überwinden. Rust ist im wahrsten Sinne des Wortes eine Revolution in der speichersicheren Systemprogrammierung, die in vielerlei Hinsicht hält, was sie verspricht... und sie rettet sicherlich den Speck von Entwicklern, die anfällig dafür sind, Fehler einzuführen, die große Probleme verursachen können, wenn sie unentdeckt bleiben. Java, C, C++ und sogar neuere Sprachen wie Kotlin und Golang sind für den sicherheitsunbewussten Entwickler ziemlich unversöhnlich. Bei diesen gibt es keine eingebauten Warnungen, keine besonderen Anzeichen dafür, dass die großartige Funktion, die gerade kompiliert wurde, einen Sicherheits-Gremlin unter der Haube versteckt hat.

Also, lassen Sie uns tiefer graben:

Was macht Rust so sicher?

Typischerweise hat ein Entwickler das primäre Ziel, Funktionen zu erstellen und sicherzustellen, dass sie funktional und benutzerfreundlich sind - vielleicht sogar Quellen des Stolzes, die er gerne in seinem Lebenslauf vorzeigen würde. Es ist völlig normal, dass ein Entwickler eine großartige Software erstellt, sie ausliefert und sich dem nächsten großen Projekt zuwendet. An diesem Punkt suchen Sicherheitsteams nach Schwachstellen, und wenn diese gefunden werden, kann es sein, dass die "fertige" Anwendung an das Team zurückgeschickt wird, um ein Hotfix zu erhalten. Das Problem kann einfach sein, oder es kann völlig außerhalb des vernünftigen Rahmens für einen Entwickler liegen, um es zu beheben.

Das Problem ist, dass die Sicherheitslücken oberflächlich betrachtet überhaupt nicht offensichtlich waren, und wenn Scannen, Testen und manuelle Codeüberprüfung sie nicht aufspüren, dann kann ein Angreifer dieses kleine Zeitfenster potenziell nutzen, um den Fehler auszunutzen.

Rust versucht zu verhindern, dass viele Schwachstellen überhaupt erst in den Code gelangen: Es wird einfach nicht kompiliert, wenn es Syntaxfehler oder andere Speichersicherheitsfehler gibt, die während des gesamten SDLCs Produktionsprobleme verursachen. Dies ist speichersichere Programmierung per Design, die sicherstellt, dass es keinen Zugriff auf ungültigen Speicher gibt (egal wie die Software ausgeführt wird). Und angesichts der Tatsache, dass 70 % aller Sicherheitsprobleme auf Probleme in der Speicherverwaltung zurückzuführen sind, ist dies eine große Leistung.

Rost wird angezeigt und verhindert:

  • Pufferüberlauf
  • Verwendung nach freier
  • Doppelfrei
  • Null-Zeiger-Dereferenz
  • Verwendung von nicht initialisiertem Speicher

Wenn wir einen Rust-Codeschnipsel mit C++ vergleichen, wird deutlich, dass der eine standardmäßig sicher ist. Sehen Sie sich dieses Beispiel eines Pufferüberlauf-Bugs an:

#include <iostream></iostream>
#include <string.h></string.h>
int main( void ) {
char a[3] = "12";
char b[4]= "123";
strcpy(a, b); // buffer overflow as len of b is greater than a
std::cout << a << "; " << b << std::endl;
}

Vs.

pub fn main() {
let mut a: [char; 2] = [1, 2];
let b: [char; 3] = [1, 2, 3];
a.copy_from_slice(&b);
}
Vergleich eines Rust-Codeausschnittes

Rust gibt eine Sicherheitswarnung aus und gerät beim Erreichen der copy_from_slice-Funktion zur Laufzeit in Panik, um einen Pufferüberlauf zu verhindern, aber nicht zur Kompilierzeit.

In diesem Sinne ist es eine der "Start Left"-Sprachen. Sie wird Fehler hervorheben und den Entwicklern die richtige Art und Weise beibringen, Code zu schreiben, um die Einführung von speicherbezogenen Sicherheitsfehlern zu vermeiden, so dass die Einhaltung von Fristen davon abhängt, dass der Programmierer aufpasst, Korrekturen vornimmt und dem Lieferpfad treu bleibt.

Der Ansatz dieser Sprache scheint einfach zu sein, aber es wäre eine unglaubliche Leistung gewesen, sie mit dieser mächtigen Logik zum Laufen zu bringen, und sie macht es auch. Aus der Sicherheitsperspektive ist Rust ein riesiger Sprung nach vorn... wenn nur mehr Menschen es verwenden würden. Unternehmen wie Dropbox leisten Pionierarbeit bei der Verwendung von Rust in großen Unternehmen, und das ist großartig zu sehen. Aber es gibt noch mehr zu bedenken, bevor wir zu dem Schluss kommen, dass die Akzeptanz das einzige ist, was uns von einer sichereren Zukunft abhält.

Die Rust-Abrechnung.

Es gibt ein paar kleine (okay, große) Probleme, nämlich, dass die Programmierung in Rust mehr Flexibilität bietet, um Fehler einzuführen, als es vielleicht den Anschein hat. Es wird die wichtigen OWASP Top 10 Schwachstellen nicht beheben, die weiterhin zu Sicherheitslücken, Verzögerungen und einer allgemeinen Kultur unsicherer Programmiertechniken führen. Es gibt auch so etwas wie eine Engel- und Teufel-Dynamik, oder, wie es allgemein bekannt ist: Sicheres Rust vs. Unsicheres Rust.

Wie in der offiziellen Dokumentation erklärt wird, ist Safe Rust die "wahre" Form von Rust, und Unsafe Rust enthält Funktionen, die als "definitiv nicht sicher" gelten, obwohl sie manchmal notwendig sind - zum Beispiel, wenn eine Integration mit etwas in einer anderen Sprache erforderlich ist. Aber auch bei Unsafe Rust ist die Liste der zusätzlichen Funktionalitäten noch begrenzt. In Unsafe Rust ist es möglich, innerhalb von unsicheren Blöcken Folgendes zu tun:

  • Dereferenzierung von Rohzeigern
  • Aufrufen unsicherer Funktionen (einschließlich C-Funktionen, Compiler-Intrinsics und dem Raw Allocator)
  • Unsichere Traits implementieren
  • Statik mutieren
  • Zugriffsfelder von Unions.

Auch im sogenannten "unsicheren" Modus funktioniert eine der Superkräfte der Rust-Programmierung: der "Borrow Checker". Er verhindert im Allgemeinen Speicherprobleme, Kollisionen bei parallelen Berechnungen und viele andere Fehler durch statische Code-Analyse, und diese Analyse wird in einem unsicheren Block immer noch Prüfungen vornehmen - es erfordert nur viel mehr Arbeit, unsichere Konstrukte zu schreiben, ohne dass der Compiler in bestimmten Situationen mit einer Anleitung eingreift.

Für die meisten erfahrenen Entwickler scheint dies kein großes Problem zu sein - schließlich sind wir dafür bekannt, zu tüfteln, um das Beste aus unseren Anwendungen herauszuholen und einige coolere Funktionen zu eröffnen -, aber es öffnet möglicherweise ein schwarzes Loch, das zu ernsthaften Fehlkonfigurationen und Sicherheitslücken führen kann: undefiniertes Verhalten. Die Programmierung in Rust (selbst bei unsicherer Verwendung) schließt die Möglichkeiten von Sicherheitslücken im Vergleich zu C oder C++ ziemlich gut ein, aber der Aufruf von undefiniertem Verhalten kann ein Risiko darstellen.

Ist dies das Ende des Vertrauens in die entwicklergeführte sichere Kodierung?

Erinnern Sie sich, als ich vorhin sagte, dass Rust Komponenten von bekannten Sprachen enthält? Eine der größten Sicherheitsschwachstellen von Rust ist, dass es Komponenten bekannter Sprachen enthält - nämlich C.

Rust ist immer noch eine "sichere Programmiersprache", aber auch hier ist die Einführung eines Benutzers der Punkt, an dem die Dinge aus dem Ruder laufen können. Der Entwickler kann es immer noch so anpassen, dass es ohne Fehlermeldung läuft (ein attraktiver Vorschlag, da dies mehr Fähigkeiten freischaltet), und im Wesentlichen können Entwickler sogar im sicheren Zustand so "unsicher" sein, wie sie wollen, weil sie eine Schicht von Anleitung und Schutz haben, bevor die Dinge wirklich birnenförmig werden können.

Und beide oben genannten Szenarien werden gefährlicher, je tiefer wir eintauchen, da die Ergebnisse von Rust denen von Scanning-Tools ähneln - so wie es kein SAST/DAST/RAST/IAST-Tool der Schweizer Armee gibt, das jede Schwachstelle, jeden Angriffsvektor und jedes Problem aufspürt, gibt es auch Rust nicht. Selbst mit Rust können einige Schwachstellen immer noch recht einfach eingeführt werden.

Das Risiko undefinierten Verhaltens bei der Verwendung von unsicherem Rust hat das Potenzial, Integer-Überlauf-Probleme auszulösen, während im Allgemeinen sogar die sicheren Konfigurationen menschliche Fehler bei Sicherheitsfehlkonfigurationen, Geschäftslogik oder der Verwendung von Komponenten mit bekannten Schwachstellen nicht verhindern können. Diese Probleme stellen immer noch eine sehr reale Bedrohung dar, wenn sie nicht gepatcht werden, und in einer "vermeintlich sicheren" Umgebung wie echtem Rust kann dies sogar zu einem selbstgefälligen Verhalten führen, wenn ein Programmierer glaubt, dass alle wichtigen Probleme trotzdem erkannt werden.

Ich habe festgestellt, dass Rust einem Mentor in der Programmierung nicht unähnlich ist - ein erfahrener Ingenieur, der sich die Zeit genommen hat, sich mit einem weniger erfahrenen Programmierer zusammenzusetzen, seine Arbeit zu überprüfen und ihm potenzielle Fehler zu zeigen, ihn auf Effizienzsteigerungen hinzuweisen und in einigen Fällen sicherzustellen, dass die Arbeit nicht kompiliert wird, bevor sie nicht richtig ist. Für Rust-Programmierer ist es jedoch weitaus besser, die Theorie zu lernen und sich selbst zu bewährten Verfahren zu verpflichten, denn der Mentor könnte die Schürze abnehmen, und Sie wollen nicht hängen gelassen werden.

Sind Sie bereit, gängige Rust-Schwachstellen zu finden und zu beheben, und zwar sofort? Spielen Sie die Herausforderung.
Ressource anzeigen
Ressource anzeigen

Füllen Sie das folgende Formular aus, um den Bericht herunterzuladen

Wir bitten Sie um Ihre Erlaubnis, Ihnen Informationen über unsere Produkte und/oder verwandte Themen der sicheren Codierung zuzusenden. Wir werden Ihre persönlichen Daten immer mit äußerster Sorgfalt behandeln und sie niemals zu Marketingzwecken an andere Unternehmen verkaufen.

Senden
Um das Formular abzuschicken, aktivieren Sie bitte "Analytics"-Cookies. Sie können die Cookies wieder deaktivieren, sobald Sie fertig sind.

In den letzten Jahren scheint es, dass Software-Ingenieure auf der ganzen Welt nicht genug von Rust bekommen können. Diese relativ neue, von Mozilla entwickelte Systemprogrammiersprache hat die Herzen der Stack Overflow-Gemeinschaft erobert - und als eine Kohorte, die keine Dummheiten duldet, ist es an der Zeit, dass wir alle aufhorchen, wenn sie etwas fünf Jahre hintereinander zur"beliebtesten Programmiersprache" wählt.

Die Programmiersprache Rust enthält bekannte und funktionale Elemente aus häufig verwendeten Sprachen und arbeitet nach einer anderen Philosophie, die Komplexität beseitigt und gleichzeitig Leistung und Sicherheit einführt. Es ist eine Lernkurve, und viele Entwickler haben nicht die Möglichkeit, viel damit zu spielen - nur 5,1 % der auf Stack Overflow befragten Personen nutzten sie häufig. Abgesehen davon lässt sich jedoch nicht leugnen, dass es sich um eine aufregende Sprache handelt, die im Vergleich zu ihren Vorgängern wie C und C++ über viel mehr Sicherheitspotenzial verfügt. Die Masseneinführung wird einige Veränderungen erfordern, sowohl in Bezug auf das Verhalten als auch auf die Technologie... aber im Moment erregt sie noch die Aufmerksamkeit von Entwicklern auf theoretischer Ebene.  

... aber Moment, wir müssen noch eine weitere Sache beleuchten: Es ist wichtig zu erwähnen, dass Rust eine Programmiersprache ist, die der Speichersicherheit und der Ausmerzung von Sicherheitsfehlern, die mit häufigen Speicherverwaltungsproblemen verbunden sind, Priorität einräumt. Diese sind eine große Sache (und verursachen zweifellos mehr als nur ein paar AppSec-Teams Migräne), aber sie sind nicht die einzigen Herausforderungen, denen wir bei der sicheren Programmierung gegenüberstehen.

Was genau wird durch Rust verhindert? Und wo gibt es noch Lücken in der Sicherheitslandschaft? Lassen Sie uns das neueste Programmier-Einhorn auspacken:

Die neue Grenze der modernen, speichersicheren Systemprogrammierung

Das Forschungs- und Entwicklungsteam von Mozilla hat an einigen unglaublichen Projekten gearbeitet, und die Investition in die Rust-Programmierung als Open-Source-Vorreiter ist keine Ausnahme. Das Einführungsvideo gibt einen Einblick in das Ethos des Teams, wobei das Hauptthema klar herausgestellt wird: Der derzeitige Ansatz zur Softwaresicherheit ist mangelhaft, und Rust wurde entwickelt, um einen Großteil dieses Problems zu lösen.

Das scheint zu simpel zu sein, zumal wir jeden Tag mit enormen Datenschutzverletzungen konfrontiert werden - wie bei dem jüngsten schrecklichen Vorfall bei EasyJet. Millionen von Datensätzen werden häufig kompromittiert, fast immer durch eine Schwachstelle in einer Webanwendung, eine falsche Sicherheitskonfiguration oder einen Phishing-Angriff, und Sprachen wie C++ gibt es schon seit Jahrzehnten. Die Zeit hat jedoch nicht ausgereicht, um sie so weit zu beherrschen, dass die besten Praktiken für eine sichere Programmierung umgesetzt werden können. Warum sollte das bei Rust anders sein? Neue Sprachen sind schon früher auf den Markt gekommen, und es ist nicht so, dass sie einen Weg gefunden hätten, allgemeine Schwachstellen auszumerzen oder sicherzustellen, dass jeder geschriebene Code beim Kompilieren auf magische Weise perfekt ist.

So einfach das Konzept auch sein mag, manchmal sind es die einfachen Antworten, die komplexe Fragen überwinden. Rust ist im wahrsten Sinne des Wortes eine Revolution in der speichersicheren Systemprogrammierung, die in vielerlei Hinsicht hält, was sie verspricht... und sie rettet sicherlich den Speck von Entwicklern, die anfällig dafür sind, Fehler einzuführen, die große Probleme verursachen können, wenn sie unentdeckt bleiben. Java, C, C++ und sogar neuere Sprachen wie Kotlin und Golang sind für den sicherheitsunbewussten Entwickler ziemlich unversöhnlich. Bei diesen gibt es keine eingebauten Warnungen, keine besonderen Anzeichen dafür, dass die großartige Funktion, die gerade kompiliert wurde, einen Sicherheits-Gremlin unter der Haube versteckt hat.

Also, lassen Sie uns tiefer graben:

Was macht Rust so sicher?

Typischerweise hat ein Entwickler das primäre Ziel, Funktionen zu erstellen und sicherzustellen, dass sie funktional und benutzerfreundlich sind - vielleicht sogar Quellen des Stolzes, die er gerne in seinem Lebenslauf vorzeigen würde. Es ist völlig normal, dass ein Entwickler eine großartige Software erstellt, sie ausliefert und sich dem nächsten großen Projekt zuwendet. An diesem Punkt suchen Sicherheitsteams nach Schwachstellen, und wenn diese gefunden werden, kann es sein, dass die "fertige" Anwendung an das Team zurückgeschickt wird, um ein Hotfix zu erhalten. Das Problem kann einfach sein, oder es kann völlig außerhalb des vernünftigen Rahmens für einen Entwickler liegen, um es zu beheben.

Das Problem ist, dass die Sicherheitslücken oberflächlich betrachtet überhaupt nicht offensichtlich waren, und wenn Scannen, Testen und manuelle Codeüberprüfung sie nicht aufspüren, dann kann ein Angreifer dieses kleine Zeitfenster potenziell nutzen, um den Fehler auszunutzen.

Rust versucht zu verhindern, dass viele Schwachstellen überhaupt erst in den Code gelangen: Es wird einfach nicht kompiliert, wenn es Syntaxfehler oder andere Speichersicherheitsfehler gibt, die während des gesamten SDLCs Produktionsprobleme verursachen. Dies ist speichersichere Programmierung per Design, die sicherstellt, dass es keinen Zugriff auf ungültigen Speicher gibt (egal wie die Software ausgeführt wird). Und angesichts der Tatsache, dass 70 % aller Sicherheitsprobleme auf Probleme in der Speicherverwaltung zurückzuführen sind, ist dies eine große Leistung.

Rost wird angezeigt und verhindert:

  • Pufferüberlauf
  • Verwendung nach freier
  • Doppelfrei
  • Null-Zeiger-Dereferenz
  • Verwendung von nicht initialisiertem Speicher

Wenn wir einen Rust-Codeschnipsel mit C++ vergleichen, wird deutlich, dass der eine standardmäßig sicher ist. Sehen Sie sich dieses Beispiel eines Pufferüberlauf-Bugs an:

#include <iostream></iostream>
#include <string.h></string.h>
int main( void ) {
char a[3] = "12";
char b[4]= "123";
strcpy(a, b); // buffer overflow as len of b is greater than a
std::cout << a << "; " << b << std::endl;
}

Vs.

pub fn main() {
let mut a: [char; 2] = [1, 2];
let b: [char; 3] = [1, 2, 3];
a.copy_from_slice(&b);
}
Vergleich eines Rust-Codeausschnittes

Rust gibt eine Sicherheitswarnung aus und gerät beim Erreichen der copy_from_slice-Funktion zur Laufzeit in Panik, um einen Pufferüberlauf zu verhindern, aber nicht zur Kompilierzeit.

In diesem Sinne ist es eine der "Start Left"-Sprachen. Sie wird Fehler hervorheben und den Entwicklern die richtige Art und Weise beibringen, Code zu schreiben, um die Einführung von speicherbezogenen Sicherheitsfehlern zu vermeiden, so dass die Einhaltung von Fristen davon abhängt, dass der Programmierer aufpasst, Korrekturen vornimmt und dem Lieferpfad treu bleibt.

Der Ansatz dieser Sprache scheint einfach zu sein, aber es wäre eine unglaubliche Leistung gewesen, sie mit dieser mächtigen Logik zum Laufen zu bringen, und sie macht es auch. Aus der Sicherheitsperspektive ist Rust ein riesiger Sprung nach vorn... wenn nur mehr Menschen es verwenden würden. Unternehmen wie Dropbox leisten Pionierarbeit bei der Verwendung von Rust in großen Unternehmen, und das ist großartig zu sehen. Aber es gibt noch mehr zu bedenken, bevor wir zu dem Schluss kommen, dass die Akzeptanz das einzige ist, was uns von einer sichereren Zukunft abhält.

Die Rust-Abrechnung.

Es gibt ein paar kleine (okay, große) Probleme, nämlich, dass die Programmierung in Rust mehr Flexibilität bietet, um Fehler einzuführen, als es vielleicht den Anschein hat. Es wird die wichtigen OWASP Top 10 Schwachstellen nicht beheben, die weiterhin zu Sicherheitslücken, Verzögerungen und einer allgemeinen Kultur unsicherer Programmiertechniken führen. Es gibt auch so etwas wie eine Engel- und Teufel-Dynamik, oder, wie es allgemein bekannt ist: Sicheres Rust vs. Unsicheres Rust.

Wie in der offiziellen Dokumentation erklärt wird, ist Safe Rust die "wahre" Form von Rust, und Unsafe Rust enthält Funktionen, die als "definitiv nicht sicher" gelten, obwohl sie manchmal notwendig sind - zum Beispiel, wenn eine Integration mit etwas in einer anderen Sprache erforderlich ist. Aber auch bei Unsafe Rust ist die Liste der zusätzlichen Funktionalitäten noch begrenzt. In Unsafe Rust ist es möglich, innerhalb von unsicheren Blöcken Folgendes zu tun:

  • Dereferenzierung von Rohzeigern
  • Aufrufen unsicherer Funktionen (einschließlich C-Funktionen, Compiler-Intrinsics und dem Raw Allocator)
  • Unsichere Traits implementieren
  • Statik mutieren
  • Zugriffsfelder von Unions.

Auch im sogenannten "unsicheren" Modus funktioniert eine der Superkräfte der Rust-Programmierung: der "Borrow Checker". Er verhindert im Allgemeinen Speicherprobleme, Kollisionen bei parallelen Berechnungen und viele andere Fehler durch statische Code-Analyse, und diese Analyse wird in einem unsicheren Block immer noch Prüfungen vornehmen - es erfordert nur viel mehr Arbeit, unsichere Konstrukte zu schreiben, ohne dass der Compiler in bestimmten Situationen mit einer Anleitung eingreift.

Für die meisten erfahrenen Entwickler scheint dies kein großes Problem zu sein - schließlich sind wir dafür bekannt, zu tüfteln, um das Beste aus unseren Anwendungen herauszuholen und einige coolere Funktionen zu eröffnen -, aber es öffnet möglicherweise ein schwarzes Loch, das zu ernsthaften Fehlkonfigurationen und Sicherheitslücken führen kann: undefiniertes Verhalten. Die Programmierung in Rust (selbst bei unsicherer Verwendung) schließt die Möglichkeiten von Sicherheitslücken im Vergleich zu C oder C++ ziemlich gut ein, aber der Aufruf von undefiniertem Verhalten kann ein Risiko darstellen.

Ist dies das Ende des Vertrauens in die entwicklergeführte sichere Kodierung?

Erinnern Sie sich, als ich vorhin sagte, dass Rust Komponenten von bekannten Sprachen enthält? Eine der größten Sicherheitsschwachstellen von Rust ist, dass es Komponenten bekannter Sprachen enthält - nämlich C.

Rust ist immer noch eine "sichere Programmiersprache", aber auch hier ist die Einführung eines Benutzers der Punkt, an dem die Dinge aus dem Ruder laufen können. Der Entwickler kann es immer noch so anpassen, dass es ohne Fehlermeldung läuft (ein attraktiver Vorschlag, da dies mehr Fähigkeiten freischaltet), und im Wesentlichen können Entwickler sogar im sicheren Zustand so "unsicher" sein, wie sie wollen, weil sie eine Schicht von Anleitung und Schutz haben, bevor die Dinge wirklich birnenförmig werden können.

Und beide oben genannten Szenarien werden gefährlicher, je tiefer wir eintauchen, da die Ergebnisse von Rust denen von Scanning-Tools ähneln - so wie es kein SAST/DAST/RAST/IAST-Tool der Schweizer Armee gibt, das jede Schwachstelle, jeden Angriffsvektor und jedes Problem aufspürt, gibt es auch Rust nicht. Selbst mit Rust können einige Schwachstellen immer noch recht einfach eingeführt werden.

Das Risiko undefinierten Verhaltens bei der Verwendung von unsicherem Rust hat das Potenzial, Integer-Überlauf-Probleme auszulösen, während im Allgemeinen sogar die sicheren Konfigurationen menschliche Fehler bei Sicherheitsfehlkonfigurationen, Geschäftslogik oder der Verwendung von Komponenten mit bekannten Schwachstellen nicht verhindern können. Diese Probleme stellen immer noch eine sehr reale Bedrohung dar, wenn sie nicht gepatcht werden, und in einer "vermeintlich sicheren" Umgebung wie echtem Rust kann dies sogar zu einem selbstgefälligen Verhalten führen, wenn ein Programmierer glaubt, dass alle wichtigen Probleme trotzdem erkannt werden.

Ich habe festgestellt, dass Rust einem Mentor in der Programmierung nicht unähnlich ist - ein erfahrener Ingenieur, der sich die Zeit genommen hat, sich mit einem weniger erfahrenen Programmierer zusammenzusetzen, seine Arbeit zu überprüfen und ihm potenzielle Fehler zu zeigen, ihn auf Effizienzsteigerungen hinzuweisen und in einigen Fällen sicherzustellen, dass die Arbeit nicht kompiliert wird, bevor sie nicht richtig ist. Für Rust-Programmierer ist es jedoch weitaus besser, die Theorie zu lernen und sich selbst zu bewährten Verfahren zu verpflichten, denn der Mentor könnte die Schürze abnehmen, und Sie wollen nicht hängen gelassen werden.

Sind Sie bereit, gängige Rust-Schwachstellen zu finden und zu beheben, und zwar sofort? Spielen Sie die Herausforderung.
Auf Ressource zugreifen

Klicken Sie auf den unten stehenden Link und laden Sie die PDF-Datei dieser Ressource herunter.

Secure Code Warrior ist für Ihr Unternehmen da, um Sie dabei zu unterstützen, Ihren Code über den gesamten Lebenszyklus der Softwareentwicklung hinweg zu sichern und eine Kultur zu schaffen, in der Cybersicherheit an erster Stelle steht. Ganz gleich, ob Sie AppSec-Manager, Entwickler, CISO oder ein anderer Sicherheitsverantwortlicher sind, wir können Ihrem Unternehmen helfen, die mit unsicherem Code verbundenen Risiken zu reduzieren.

Bericht ansehenDemo buchen
PDF herunterladen
Ressource anzeigen
Weitergeben:
Interessiert an mehr?

Weitergeben:
Autor
Matias Madou, Ph.D.
Veröffentlicht Jun 18, 2020

Matias Madou, Ph.D., ist Sicherheitsexperte, Forscher, CTO und Mitbegründer von Secure Code Warrior. Matias promovierte an der Universität Gent im Bereich Anwendungssicherheit und konzentrierte sich dabei auf statische Analyselösungen. Später wechselte er zu Fortify in den USA, wo er erkannte, dass es nicht ausreicht, nur Codeprobleme zu erkennen, ohne den Entwicklern beim Schreiben von sicherem Code zu helfen. Dies inspirierte ihn dazu, Produkte zu entwickeln, die Entwickler unterstützen, den Aufwand für die Sicherheit verringern und die Erwartungen der Kunden übertreffen. Wenn er nicht an seinem Schreibtisch im Team Awesome sitzt, steht er gerne auf der Bühne und hält Vorträge auf Konferenzen wie der RSA Conference, BlackHat und DefCon.

Matias ist ein Forscher und Entwickler mit mehr als 15 Jahren praktischer Erfahrung im Bereich der Softwaresicherheit. Er hat Lösungen für Unternehmen wie Fortify Software und sein eigenes Unternehmen Sensei Security entwickelt. Im Laufe seiner Karriere hat Matias mehrere Forschungsprojekte zur Anwendungssicherheit geleitet, die zu kommerziellen Produkten geführt haben, und kann auf über 10 Patente verweisen. Wenn er nicht am Schreibtisch sitzt, ist Matias als Ausbilder für fortgeschrittene Anwendungssicherheitstrainings courses tätig und hält regelmäßig Vorträge auf globalen Konferenzen wie RSA Conference, Black Hat, DefCon, BSIMM, OWASP AppSec und BruCon.

Matias hat einen Doktortitel in Computertechnik von der Universität Gent, wo er die Sicherheit von Anwendungen durch Programmverschleierung untersuchte, um die innere Funktionsweise einer Anwendung zu verbergen.

Weitergeben:

In den letzten Jahren scheint es, dass Software-Ingenieure auf der ganzen Welt nicht genug von Rust bekommen können. Diese relativ neue, von Mozilla entwickelte Systemprogrammiersprache hat die Herzen der Stack Overflow-Gemeinschaft erobert - und als eine Kohorte, die keine Dummheiten duldet, ist es an der Zeit, dass wir alle aufhorchen, wenn sie etwas fünf Jahre hintereinander zur"beliebtesten Programmiersprache" wählt.

Die Programmiersprache Rust enthält bekannte und funktionale Elemente aus häufig verwendeten Sprachen und arbeitet nach einer anderen Philosophie, die Komplexität beseitigt und gleichzeitig Leistung und Sicherheit einführt. Es ist eine Lernkurve, und viele Entwickler haben nicht die Möglichkeit, viel damit zu spielen - nur 5,1 % der auf Stack Overflow befragten Personen nutzten sie häufig. Abgesehen davon lässt sich jedoch nicht leugnen, dass es sich um eine aufregende Sprache handelt, die im Vergleich zu ihren Vorgängern wie C und C++ über viel mehr Sicherheitspotenzial verfügt. Die Masseneinführung wird einige Veränderungen erfordern, sowohl in Bezug auf das Verhalten als auch auf die Technologie... aber im Moment erregt sie noch die Aufmerksamkeit von Entwicklern auf theoretischer Ebene.  

... aber Moment, wir müssen noch eine weitere Sache beleuchten: Es ist wichtig zu erwähnen, dass Rust eine Programmiersprache ist, die der Speichersicherheit und der Ausmerzung von Sicherheitsfehlern, die mit häufigen Speicherverwaltungsproblemen verbunden sind, Priorität einräumt. Diese sind eine große Sache (und verursachen zweifellos mehr als nur ein paar AppSec-Teams Migräne), aber sie sind nicht die einzigen Herausforderungen, denen wir bei der sicheren Programmierung gegenüberstehen.

Was genau wird durch Rust verhindert? Und wo gibt es noch Lücken in der Sicherheitslandschaft? Lassen Sie uns das neueste Programmier-Einhorn auspacken:

Die neue Grenze der modernen, speichersicheren Systemprogrammierung

Das Forschungs- und Entwicklungsteam von Mozilla hat an einigen unglaublichen Projekten gearbeitet, und die Investition in die Rust-Programmierung als Open-Source-Vorreiter ist keine Ausnahme. Das Einführungsvideo gibt einen Einblick in das Ethos des Teams, wobei das Hauptthema klar herausgestellt wird: Der derzeitige Ansatz zur Softwaresicherheit ist mangelhaft, und Rust wurde entwickelt, um einen Großteil dieses Problems zu lösen.

Das scheint zu simpel zu sein, zumal wir jeden Tag mit enormen Datenschutzverletzungen konfrontiert werden - wie bei dem jüngsten schrecklichen Vorfall bei EasyJet. Millionen von Datensätzen werden häufig kompromittiert, fast immer durch eine Schwachstelle in einer Webanwendung, eine falsche Sicherheitskonfiguration oder einen Phishing-Angriff, und Sprachen wie C++ gibt es schon seit Jahrzehnten. Die Zeit hat jedoch nicht ausgereicht, um sie so weit zu beherrschen, dass die besten Praktiken für eine sichere Programmierung umgesetzt werden können. Warum sollte das bei Rust anders sein? Neue Sprachen sind schon früher auf den Markt gekommen, und es ist nicht so, dass sie einen Weg gefunden hätten, allgemeine Schwachstellen auszumerzen oder sicherzustellen, dass jeder geschriebene Code beim Kompilieren auf magische Weise perfekt ist.

So einfach das Konzept auch sein mag, manchmal sind es die einfachen Antworten, die komplexe Fragen überwinden. Rust ist im wahrsten Sinne des Wortes eine Revolution in der speichersicheren Systemprogrammierung, die in vielerlei Hinsicht hält, was sie verspricht... und sie rettet sicherlich den Speck von Entwicklern, die anfällig dafür sind, Fehler einzuführen, die große Probleme verursachen können, wenn sie unentdeckt bleiben. Java, C, C++ und sogar neuere Sprachen wie Kotlin und Golang sind für den sicherheitsunbewussten Entwickler ziemlich unversöhnlich. Bei diesen gibt es keine eingebauten Warnungen, keine besonderen Anzeichen dafür, dass die großartige Funktion, die gerade kompiliert wurde, einen Sicherheits-Gremlin unter der Haube versteckt hat.

Also, lassen Sie uns tiefer graben:

Was macht Rust so sicher?

Typischerweise hat ein Entwickler das primäre Ziel, Funktionen zu erstellen und sicherzustellen, dass sie funktional und benutzerfreundlich sind - vielleicht sogar Quellen des Stolzes, die er gerne in seinem Lebenslauf vorzeigen würde. Es ist völlig normal, dass ein Entwickler eine großartige Software erstellt, sie ausliefert und sich dem nächsten großen Projekt zuwendet. An diesem Punkt suchen Sicherheitsteams nach Schwachstellen, und wenn diese gefunden werden, kann es sein, dass die "fertige" Anwendung an das Team zurückgeschickt wird, um ein Hotfix zu erhalten. Das Problem kann einfach sein, oder es kann völlig außerhalb des vernünftigen Rahmens für einen Entwickler liegen, um es zu beheben.

Das Problem ist, dass die Sicherheitslücken oberflächlich betrachtet überhaupt nicht offensichtlich waren, und wenn Scannen, Testen und manuelle Codeüberprüfung sie nicht aufspüren, dann kann ein Angreifer dieses kleine Zeitfenster potenziell nutzen, um den Fehler auszunutzen.

Rust versucht zu verhindern, dass viele Schwachstellen überhaupt erst in den Code gelangen: Es wird einfach nicht kompiliert, wenn es Syntaxfehler oder andere Speichersicherheitsfehler gibt, die während des gesamten SDLCs Produktionsprobleme verursachen. Dies ist speichersichere Programmierung per Design, die sicherstellt, dass es keinen Zugriff auf ungültigen Speicher gibt (egal wie die Software ausgeführt wird). Und angesichts der Tatsache, dass 70 % aller Sicherheitsprobleme auf Probleme in der Speicherverwaltung zurückzuführen sind, ist dies eine große Leistung.

Rost wird angezeigt und verhindert:

  • Pufferüberlauf
  • Verwendung nach freier
  • Doppelfrei
  • Null-Zeiger-Dereferenz
  • Verwendung von nicht initialisiertem Speicher

Wenn wir einen Rust-Codeschnipsel mit C++ vergleichen, wird deutlich, dass der eine standardmäßig sicher ist. Sehen Sie sich dieses Beispiel eines Pufferüberlauf-Bugs an:

#include <iostream></iostream>
#include <string.h></string.h>
int main( void ) {
char a[3] = "12";
char b[4]= "123";
strcpy(a, b); // buffer overflow as len of b is greater than a
std::cout << a << "; " << b << std::endl;
}

Vs.

pub fn main() {
let mut a: [char; 2] = [1, 2];
let b: [char; 3] = [1, 2, 3];
a.copy_from_slice(&b);
}
Vergleich eines Rust-Codeausschnittes

Rust gibt eine Sicherheitswarnung aus und gerät beim Erreichen der copy_from_slice-Funktion zur Laufzeit in Panik, um einen Pufferüberlauf zu verhindern, aber nicht zur Kompilierzeit.

In diesem Sinne ist es eine der "Start Left"-Sprachen. Sie wird Fehler hervorheben und den Entwicklern die richtige Art und Weise beibringen, Code zu schreiben, um die Einführung von speicherbezogenen Sicherheitsfehlern zu vermeiden, so dass die Einhaltung von Fristen davon abhängt, dass der Programmierer aufpasst, Korrekturen vornimmt und dem Lieferpfad treu bleibt.

Der Ansatz dieser Sprache scheint einfach zu sein, aber es wäre eine unglaubliche Leistung gewesen, sie mit dieser mächtigen Logik zum Laufen zu bringen, und sie macht es auch. Aus der Sicherheitsperspektive ist Rust ein riesiger Sprung nach vorn... wenn nur mehr Menschen es verwenden würden. Unternehmen wie Dropbox leisten Pionierarbeit bei der Verwendung von Rust in großen Unternehmen, und das ist großartig zu sehen. Aber es gibt noch mehr zu bedenken, bevor wir zu dem Schluss kommen, dass die Akzeptanz das einzige ist, was uns von einer sichereren Zukunft abhält.

Die Rust-Abrechnung.

Es gibt ein paar kleine (okay, große) Probleme, nämlich, dass die Programmierung in Rust mehr Flexibilität bietet, um Fehler einzuführen, als es vielleicht den Anschein hat. Es wird die wichtigen OWASP Top 10 Schwachstellen nicht beheben, die weiterhin zu Sicherheitslücken, Verzögerungen und einer allgemeinen Kultur unsicherer Programmiertechniken führen. Es gibt auch so etwas wie eine Engel- und Teufel-Dynamik, oder, wie es allgemein bekannt ist: Sicheres Rust vs. Unsicheres Rust.

Wie in der offiziellen Dokumentation erklärt wird, ist Safe Rust die "wahre" Form von Rust, und Unsafe Rust enthält Funktionen, die als "definitiv nicht sicher" gelten, obwohl sie manchmal notwendig sind - zum Beispiel, wenn eine Integration mit etwas in einer anderen Sprache erforderlich ist. Aber auch bei Unsafe Rust ist die Liste der zusätzlichen Funktionalitäten noch begrenzt. In Unsafe Rust ist es möglich, innerhalb von unsicheren Blöcken Folgendes zu tun:

  • Dereferenzierung von Rohzeigern
  • Aufrufen unsicherer Funktionen (einschließlich C-Funktionen, Compiler-Intrinsics und dem Raw Allocator)
  • Unsichere Traits implementieren
  • Statik mutieren
  • Zugriffsfelder von Unions.

Auch im sogenannten "unsicheren" Modus funktioniert eine der Superkräfte der Rust-Programmierung: der "Borrow Checker". Er verhindert im Allgemeinen Speicherprobleme, Kollisionen bei parallelen Berechnungen und viele andere Fehler durch statische Code-Analyse, und diese Analyse wird in einem unsicheren Block immer noch Prüfungen vornehmen - es erfordert nur viel mehr Arbeit, unsichere Konstrukte zu schreiben, ohne dass der Compiler in bestimmten Situationen mit einer Anleitung eingreift.

Für die meisten erfahrenen Entwickler scheint dies kein großes Problem zu sein - schließlich sind wir dafür bekannt, zu tüfteln, um das Beste aus unseren Anwendungen herauszuholen und einige coolere Funktionen zu eröffnen -, aber es öffnet möglicherweise ein schwarzes Loch, das zu ernsthaften Fehlkonfigurationen und Sicherheitslücken führen kann: undefiniertes Verhalten. Die Programmierung in Rust (selbst bei unsicherer Verwendung) schließt die Möglichkeiten von Sicherheitslücken im Vergleich zu C oder C++ ziemlich gut ein, aber der Aufruf von undefiniertem Verhalten kann ein Risiko darstellen.

Ist dies das Ende des Vertrauens in die entwicklergeführte sichere Kodierung?

Erinnern Sie sich, als ich vorhin sagte, dass Rust Komponenten von bekannten Sprachen enthält? Eine der größten Sicherheitsschwachstellen von Rust ist, dass es Komponenten bekannter Sprachen enthält - nämlich C.

Rust ist immer noch eine "sichere Programmiersprache", aber auch hier ist die Einführung eines Benutzers der Punkt, an dem die Dinge aus dem Ruder laufen können. Der Entwickler kann es immer noch so anpassen, dass es ohne Fehlermeldung läuft (ein attraktiver Vorschlag, da dies mehr Fähigkeiten freischaltet), und im Wesentlichen können Entwickler sogar im sicheren Zustand so "unsicher" sein, wie sie wollen, weil sie eine Schicht von Anleitung und Schutz haben, bevor die Dinge wirklich birnenförmig werden können.

Und beide oben genannten Szenarien werden gefährlicher, je tiefer wir eintauchen, da die Ergebnisse von Rust denen von Scanning-Tools ähneln - so wie es kein SAST/DAST/RAST/IAST-Tool der Schweizer Armee gibt, das jede Schwachstelle, jeden Angriffsvektor und jedes Problem aufspürt, gibt es auch Rust nicht. Selbst mit Rust können einige Schwachstellen immer noch recht einfach eingeführt werden.

Das Risiko undefinierten Verhaltens bei der Verwendung von unsicherem Rust hat das Potenzial, Integer-Überlauf-Probleme auszulösen, während im Allgemeinen sogar die sicheren Konfigurationen menschliche Fehler bei Sicherheitsfehlkonfigurationen, Geschäftslogik oder der Verwendung von Komponenten mit bekannten Schwachstellen nicht verhindern können. Diese Probleme stellen immer noch eine sehr reale Bedrohung dar, wenn sie nicht gepatcht werden, und in einer "vermeintlich sicheren" Umgebung wie echtem Rust kann dies sogar zu einem selbstgefälligen Verhalten führen, wenn ein Programmierer glaubt, dass alle wichtigen Probleme trotzdem erkannt werden.

Ich habe festgestellt, dass Rust einem Mentor in der Programmierung nicht unähnlich ist - ein erfahrener Ingenieur, der sich die Zeit genommen hat, sich mit einem weniger erfahrenen Programmierer zusammenzusetzen, seine Arbeit zu überprüfen und ihm potenzielle Fehler zu zeigen, ihn auf Effizienzsteigerungen hinzuweisen und in einigen Fällen sicherzustellen, dass die Arbeit nicht kompiliert wird, bevor sie nicht richtig ist. Für Rust-Programmierer ist es jedoch weitaus besser, die Theorie zu lernen und sich selbst zu bewährten Verfahren zu verpflichten, denn der Mentor könnte die Schürze abnehmen, und Sie wollen nicht hängen gelassen werden.

Sind Sie bereit, gängige Rust-Schwachstellen zu finden und zu beheben, und zwar sofort? Spielen Sie die Herausforderung.

Inhaltsübersicht

PDF herunterladen
Ressource anzeigen
Interessiert an mehr?

Matias Madou, Ph.D., ist Sicherheitsexperte, Forscher, CTO und Mitbegründer von Secure Code Warrior. Matias promovierte an der Universität Gent im Bereich Anwendungssicherheit und konzentrierte sich dabei auf statische Analyselösungen. Später wechselte er zu Fortify in den USA, wo er erkannte, dass es nicht ausreicht, nur Codeprobleme zu erkennen, ohne den Entwicklern beim Schreiben von sicherem Code zu helfen. Dies inspirierte ihn dazu, Produkte zu entwickeln, die Entwickler unterstützen, den Aufwand für die Sicherheit verringern und die Erwartungen der Kunden übertreffen. Wenn er nicht an seinem Schreibtisch im Team Awesome sitzt, steht er gerne auf der Bühne und hält Vorträge auf Konferenzen wie der RSA Conference, BlackHat und DefCon.

Secure Code Warrior ist für Ihr Unternehmen da, um Sie dabei zu unterstützen, Ihren Code über den gesamten Lebenszyklus der Softwareentwicklung hinweg zu sichern und eine Kultur zu schaffen, in der Cybersicherheit an erster Stelle steht. Ganz gleich, ob Sie AppSec-Manager, Entwickler, CISO oder ein anderer Sicherheitsverantwortlicher sind, wir können Ihrem Unternehmen helfen, die mit unsicherem Code verbundenen Risiken zu reduzieren.

Demo buchenHerunterladen
Weitergeben:
Ressourcendrehscheibe

Ressourcen für den Einstieg

Mehr Beiträge
Ressourcendrehscheibe

Ressourcen für den Einstieg

Mehr Beiträge