Sicherheit von Rust-Anwendungen: Top-10 Schwachstellen für Anfänger

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: Top-10 Schwachstellen für Anfänger

\n\n

Rust gilt dank seines Ownership-Systems und der strengen Typisierung als eine der sichersten Programmiersprachen. Dennoch können auch in Rust Fehler passieren, insbesondere bei der Verwendung von unsafe-Blöcken oder bei falscher Arbeit mit externen Bibliotheken. In diesem Artikel analysieren wir die Top-10 Schwachstellen, auf die Anfänger in Rust stoßen, und zeigen, wie man sie vermeidet.

\n\n

1. Unsichere Verwendung von unsafe-Code

\n\n

Das Hauptmerkmal von Rust ist die Speichersicherheit ohne Garbage Collector. Das Schlüsselwort unsafe deaktiviert jedoch einige Compiler-Prüfungen. Anfänger missbrauchen es oft, ohne die Konsequenzen zu verstehen.

\n\n
// Gefährlich: Dereferenzierung eines rohen Zeigers ohne Prüfung\nfn dangerous() {\n    let ptr = 0x12345 as *const i32;\n    unsafe {\n        println!("Wert: {}", *ptr); // Kann einen Segfault auslösen\n    }\n}\n\n// Sicher: Verwendung geprüfter Methoden\nfn safe() {\n    let x = 42;\n    let ptr = &x as *const i32;\n    unsafe {\n        if !ptr.is_null() {\n            println!("Wert: {}", *ptr);\n        }\n    }\n}
\n\n

Empfehlung: Verwenden Sie unsafe nur, wenn es wirklich notwendig ist, und überprüfen Sie Zeiger immer auf null.

\n\n

2. Speicherlecks durch Box::leak und Rc-Zyklen

\n\n

Obwohl Rust die meisten Speicherlecks verhindert, können zyklische Referenzen mit Rc oder RefCell zu Lecks führen. Auch Box::leak ist gefährlich, da es Speicher absichtlich "vergisst".

\n\n
use std::rc::Rc;\nuse std::cell::RefCell;\n\n#[derive(Debug)]\nstruct Node {\n    value: i32,\n    next: Option<Rc<RefCell<Node>>>,\n}\n\nfn create_cycle() {\n    let a = Rc::new(RefCell::new(Node { value: 1, next: None }));\n    let b = Rc::new(RefCell::new(Node { value: 2, next: None }));\n    \n    // Zyklus erstellen: a -> b -> a\n    a.borrow_mut().next = Some(b.clone());\n    b.borrow_mut().next = Some(a.clone());\n    // Speicher wird nie freigegeben!\n}
\n\n

Lösung: Verwenden Sie Weak<T> zum Aufbrechen zyklischer Referenzen oder überdenken Sie die Architektur.

\n\n

3. Datenrennen (Data Races) in Multithread-Code

\n\n

Rust garantiert das Fehlen von Datenrennen in sicherem Code, aber bei falscher Verwendung von unsafe oder der Send/Sync-Traits können Probleme auftreten.

\n\n
use std::thread;\nuse std::sync::Arc;\nuse std::sync::Mutex;\n\n// Gefährlich: Gemeinsamer veränderlicher Zustand ohne Synchronisation\nfn data_race_example() {\n    let mut counter = 0;\n    let mut handles = vec![];\n    \n    for _ in 0..10 {\n        handles.push(thread::spawn(|| {\n            counter += 1; // Compiler-Fehler: cannot borrow\n        }));\n    }\n}\n\n// Sicher: Verwendung von Mutex\nfn safe_mutex() {\n    let counter = Arc::new(Mutex::new(0));\n    let mut handles = vec![];\n    \n    for _ in 0..10 {\n        let counter = Arc::clone(&counter);\n        handles.push(thread::spawn(move || {\n            let mut num = counter.lock().unwrap();\n            *num += 1;\n        }));\n    }\n}
\n\n

4. Pufferüberlauf (Buffer Overflow)

\n\n

In Rust ist ein Pufferüberlauf in sicherem Code unwahrscheinlich, aber möglich bei Verwendung von unsafe oder bei der Arbeit mit FFI (Foreign Function Interface).

\n\n
// Gefährlich: Unsicheres Kopieren in einen Puffer\nfn unsafe_copy(src: &[u8], dst: &mut [u8]) {\n    unsafe {\n        std::ptr::copy_nonoverlapping(\n            src.as_ptr(),\n            dst.as_mut_ptr(),\n            src.len() // Wenn src.len() > dst.len() - Überlauf!\n        );\n    }\n}\n\n// Sicher: Verwendung von slice::copy_from_slice\nfn safe_copy(src: &[u8], dst: &mut [u8]) {\n    if src.len() <= dst.len                

Blogs

Buchempfehlungen