Sicherheit von Rust-Anwendungen: Die Top-10 Schwachstellen in der Praxis

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Sicherheit von Rust-Anwendungen: Die Top-10 Schwachstellen in der Praxis



Rust positioniert sich als sichere systemnahe Sprache, die ganze Fehlerklassen verhindern kann, die für C und C++ typisch sind. Dies bedeutet jedoch nicht, dass Rust-Anwendungen unverwundbar sind. Das Ownership-System und der Borrow Checker schützen vor vielen Problemen, aber unsicherer Code, logische Fehler und externe Abhängigkeiten eröffnen neue Angriffsvektoren. In diesem Artikel analysieren wir die 10 kritischsten Schwachstellen, auf die Rust-Entwickler stoßen – mit realen Codebeispielen und praktischen Tipps zu deren Behebung.



Das Material ist sowohl für Anfänger als auch für erfahrene Ingenieure nützlich, die ihr Wissen über Sicherheit im Rust-Ökosystem vertiefen möchten.



1. Unsichere Verwendung von unsafe



Das Schlüsselwort unsafe ist die häufigste Quelle für Schwachstellen in Rust. Es deaktiviert die Prüfungen des Borrow Checkers und ermöglicht die Arbeit mit rohen Zeigern, aber die Verantwortung für die Korrektheit liegt vollständig beim Entwickler.



// Verwundbarer Code: Dereferenzierung eines Nullzeigersfn dangerous() {    let ptr: *const i32 = std::ptr::null();    unsafe {        println!("{}", *ptr); // UB! Segfault    }}


Lösung: Minimieren Sie die Verwendung von unsafe. Lagern Sie gefährliche Operationen in separate Module mit gründlichem Testen und Dokumentieren der Invarianten aus. Verwenden Sie NonNull<T> anstelle von rohen Zeigern.



2. Datenrennen (Data Races)



Obwohl der Borrow Checker Datenrennen in sicherem Code verhindert, können unsafe und die falsche Verwendung von Synchronisationsprimitiven zu Race Conditions führen.



// Verwundbarer Code: Datenrennen durch unsafestatic mut COUNTER: i32 = 0;

fn increment() { unsafe { COUNTER += 1; // Nicht-atomare Operation }}


Lösung: Verwenden Sie AtomicI32, Mutex oder RwLock. In sicherem Rust-Code sind Datenrennen unmöglich – vertrauen Sie dem Compiler.



3. Integer Overflow (Ganzzahlüberlauf)



Im Debug-Modus führt Rust bei einem Überlauf zu einer Panik, aber im Release-Modus erfolgt standardmäßig ein Wrapping (zyklischer Überlauf), was zu unerwartetem Verhalten führen kann.



// Potenzielle Schwachstelle: Überlauflogikfn allocate_buffer(size: usize) {    let header_size = 64;    let total = size + header_size; // Kann überlaufen    let buf = vec![0u8; total]; // Panik oder kleiner Puffer}


Lösung: Verwenden Sie die Methoden checked_add(), saturating_add() oder eine explizite Prüfung. Für kritische Berechnungen verwenden Sie die Crate overflow-checks.



4. Speicherlecks in unsafe-Code



Rust garantiert das Fehlen von Speicherlecks in sicherem Code, aber unsafe kann dieses Prinzip verletzen. Zum Beispiel durch falsche Verwaltung von rohen Zeigern oder zyklische Referenzen mit Rc.



// Speicherleck: drop wurde vergessenfn leak_memory() {    let ptr = Box::into_raw(Box::new(42));    // ptr wurde nicht freigegeben – Speicherleck}


Lösung: Verwenden Sie Box::from_raw() zur korrekten Freigabe. Für zyklische Referenzen verwenden Sie Weak oder Arc.



5. Unsichere FFI-Aufrufe



Aufrufe von C-Funktionen über FFI (Foreign Function Interface) sind eine der Hauptquellen für Schwachstellen. Rust kann die Sicherheit von externem Code nicht kontrollieren.



// Gefährliches FFI: Übergabe eines ungültigen Zeigersextern "C" {    fn c_free(ptr: *mut c_void);}

fn free_wrapper(ptr: *mut c_void) { unsafe { c_free(ptr); } // Doppelte Freigabe?}


Lösung: Verwenden Sie sichere Wrapper, überprüfen Sie Puffergrenzen, verwenden Sie std::ffi::CStr für Zeichenketten

Blogs

Buchempfehlungen