Segurança de aplicações Rust: top 10 vulnerabilidades

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Introdução: Mitos e Realidade da Segurança em Rust

A linguagem Rust é frequentemente chamada de "segura" e "confiável", e isso é em grande parte verdade. Graças ao sistema de ownership (propriedade) e ao compilador rigoroso, Rust elimina classes inteiras de vulnerabilidades características de C e C++ (por exemplo, estouro de buffer ou ponteiros soltos). No entanto, isso não significa que aplicações Rust são invulneráveis. Na prática, desenvolvedores enfrentam erros de lógica, uso incorreto de unsafe e vulnerabilidades no nível da arquitetura.

Neste artigo, vamos analisar o top 10 das vulnerabilidades mais frequentes em aplicações Rust. Você aprenderá como elas surgem, como detectá-las e como proteger seu código. O material será útil tanto para iniciantes quanto para desenvolvedores experientes.



1. Erros em código unsafe

O "calcanhar de Aquiles" mais conhecido do Rust são os blocos unsafe. Eles permitem executar operações que o compilador não pode verificar: desreferenciar ponteiros crus, chamar funções externas (FFI), alterar variáveis estáticas. Se um erro for cometido em unsafe, toda a segurança do Rust desmorona.

Exemplo de vulnerabilidade

fn unsafe_deref(ptr: *const i32) -> i32 {    unsafe { *ptr } // Se ptr for nulo ou apontar para memória liberada — UB

Como se proteger

  • Minimize o uso de unsafe. Isole-o em módulos pequenos e cuidadosamente testados.
  • Use #[deny(unsafe_code)] em crates onde for possível.
  • Verifique a validade dos ponteiros antes de desreferenciá-los.


2. Condições de Corrida (Data Races) em código multithread

Rust garante a ausência de data races em código seguro graças às regras de ownership e borrowing. No entanto, ao usar unsafe ou trabalhar incorretamente com Mutex/RwLock, data races são possíveis. Situações com Cell/RefCell em ambiente multithread são particularmente perigosas.

Exemplo de vulnerabilidade

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

fn main() { let data = RefCell::new(0); thread::spawn(move || { *data.borrow_mut() += 1; // Pânico: RefCell não é Sync });}

Como se proteger

  • Use Arc<Mutex<T>> ou Arc<RwLock<T>> para dados compartilhados.
  • Evite unsafe ao trabalhar com threads, a menos que seja absolutamente necessário.
  • Aplique o analisador estático clippy e o miri para detectar comportamento indefinido.


3. Vazamentos de Memória (Memory Leaks)

Embora Rust previna vazamentos na maioria dos casos, eles ainda são possíveis. Por exemplo, ao criar referências cíclicas com Rc/RefCell ou ao esquecer de chamar o destrutor em código unsafe. Vazamentos de memória em serviços de longa duração podem levar ao esgotamento de recursos.

Exemplo de vulnerabilidade

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); // Referência cíclica — vazamento}

Como se proteger

  • Use Weak para quebrar referências cíclicas.
  • Para aplicações de longa duração, utilize profileadores de memória (por exemplo, valgrind ou heaptrack).
  • Em código unsafe, sempre verifique se a memória está sendo liberada corretamente.


4. Tratamento Incorreto de Erros

Rust incentiva o tratamento explícito de erros através de Result e Option. No entanto, desenvolvedores frequentemente ignoram erros usando .unwrap() ou .expect(). Em produção, isso pode le

Blogs

Book Recommendations