Sécurité des applications Rust : top 10 des vulnérabilités

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Introduction : Mythes et réalité de la sécurité de Rust

Le langage Rust est souvent qualifié de "sûr" et "fiable", ce qui est en grande partie vrai. Grâce à son système de possession (ownership) et à son compilateur strict, Rust élimine des classes entières de vulnérabilités typiques de C et C++ (par exemple, les débordements de tampon ou les pointeurs pendants). Cependant, cela ne signifie pas que les applications Rust sont invulnérables. En pratique, les développeurs rencontrent des erreurs de logique, une mauvaise utilisation de unsafe et des vulnérabilités au niveau architectural.

Dans cet article, nous allons analyser le top 10 des vulnérabilités les plus fréquentes dans les applications Rust. Vous apprendrez comment elles surviennent, comment les détecter et comment sécuriser votre code. Ce contenu sera utile aussi bien aux débutants qu'aux développeurs expérimentés.

1. Erreurs dans le code unsafe

Le "talon d'Achille" le plus connu de Rust est les blocs unsafe. Ils permettent d'effectuer des opérations que le compilateur ne peut pas vérifier : déréférencement de pointeurs bruts, appel de fonctions externes (FFI), modification de variables statiques. Si une erreur est commise dans unsafe, toute la sécurité de Rust s'effondre.

Exemple de vulnérabilité

fn unsafe_deref(ptr: *const i32) -> i32 {    unsafe { *ptr } // Si ptr est nul ou pointe vers de la mémoire libérée — UB}

Comment se protéger

  • Minimisez l'utilisation de unsafe. Placez-le dans des modules petits et minutieusement testés.
  • Utilisez #[deny(unsafe_code)] dans les crates lorsque c'est possible.
  • Vérifiez la validité des pointeurs avant de les déréférencer.

2. Courses de données (Data Races) dans le code multithreadé

Rust garantit l'absence de courses de données dans le code sûr grâce aux règles de possession et d'emprunt. Cependant, lors de l'utilisation de unsafe ou d'une mauvaise manipulation de Mutex/RwLock, des courses sont possibles. Les situations avec Cell/RefCell dans un environnement multithreadé sont particulièrement dangereuses.

Exemple de vulnérabilité

use std::cell::RefCell;use std::thread;

fn main() { let data = RefCell::new(0); thread::spawn(move || { *data.borrow_mut() += 1; // Panique : RefCell n'est pas Sync });}

Comment se protéger

  • Utilisez Arc<Mutex<T>> ou Arc<RwLock<T>> pour les données partagées.
  • Évitez unsafe lors du travail avec les threads sauf en cas de nécessité absolue.
  • Appliquez l'analyseur statique clippy et miri pour détecter les comportements indéfinis.

3. Fuites de mémoire (Memory Leaks)

Bien que Rust prévienne les fuites dans la plupart des cas, elles sont toujours possibles. Par exemple, lors de la création de références cycliques avec Rc/RefCell ou en oubliant d'appeler le destructeur dans du code unsafe. Les fuites de mémoire dans les services à longue durée de vie peuvent entraîner un épuisement des ressources.

Exemple de vulnérabilité

use std::rc::Rc;use std::cell::RefCell;

struct Node { next: Option<Rc<RefCell<Node>>>,}

fn main() { let a = Rc::new(RefCell::new(Node { next: None })); let b = Rc::new(RefCell::new(Node { next: Some(a.clone()) })); a.borrow_mut().next = Some(b); // Référence cyclique — fuite}

Comment se protéger

  • Utilisez Weak pour briser les références cycliques.
  • Pour les applications à longue durée de vie, utilisez des profileurs de mémoire (par exemple, valgrind ou heaptrack).
  • Dans le code unsafe, vérifiez toujours que la mémoire est libérée correctement.

4. Gestion incorrecte des erreurs

Rust encourage la gestion explicite des erreurs via Result et Option. Cependant, les développeurs ignorent souvent les erreurs en utilisant .unwrap() ou .expect(). En production, cela peut en

Blogs

Book Recommendations