Segurança de aplicações Rust: top 10 vulnerabilidades na prática

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

Segurança de aplicações Rust: top 10 vulnerabilidades na prática



Rust é posicionado como uma linguagem de sistema segura, capaz de prevenir classes inteiras de erros típicos de C e C++. No entanto, isso não significa que aplicações Rust sejam invulneráveis. O sistema de ownership e o borrow checker protegem contra muitos problemas, mas código unsafe, erros lógicos e dependências externas abrem novos vetores de ataque. Neste artigo, analisaremos as 10 vulnerabilidades mais críticas que desenvolvedores Rust enfrentam — com exemplos reais de código e dicas práticas para corrigi-las.



O material será útil tanto para iniciantes quanto para engenheiros experientes que desejam aprofundar seus conhecimentos sobre segurança no ecossistema Rust.



1. Uso inseguro de unsafe



A palavra-chave unsafe é a fonte mais comum de vulnerabilidades em Rust. Ela desativa as verificações do borrow checker e permite trabalhar com ponteiros brutos, mas a responsabilidade pela correção recai totalmente sobre o desenvolvedor.



// Código vulnerável: desreferenciamento de ponteiro nulofn dangerous() {    let ptr: *const i32 = std::ptr::null();    unsafe {        println!("{}", *ptr); // UB! Segfault    }}


Solução: minimize o uso de unsafe. Isole operações perigosas em módulos separados com testes rigorosos e documentação de invariantes. Use NonNull<T> em vez de ponteiros brutos.



2. Condições de corrida (Data Races)



Embora o borrow checker previna corridas em código seguro, o unsafe e o uso incorreto de primitivas de sincronização podem levar a condições de corrida.



// Código vulnerável: condição de corrida via unsafestatic mut COUNTER: i32 = 0;

fn increment() { unsafe { COUNTER += 1; // Operação não atômica }}


Solução: use AtomicI32, Mutex ou RwLock. Em código Rust seguro, condições de corrida são impossíveis — confie no compilador.



3. Integer Overflow (estouro de inteiros)



No modo debug, Rust entra em pânico em caso de estouro, mas no modo release, o comportamento padrão é wrapping (transbordo cíclico), o que pode levar a comportamentos inesperados.



// Vulnerabilidade potencial: lógica de estourofn allocate_buffer(size: usize) {    let header_size = 64;    let total = size + header_size; // Pode estourar    let buf = vec![0u8; total]; // Pânico ou buffer pequeno}


Solução: use os métodos checked_add(), saturating_add() ou verificação explícita. Para cálculos críticos, utilize a crate overflow-checks.



4. Vazamentos de memória em código unsafe



Rust garante a ausência de vazamentos em código seguro, mas o unsafe pode violar esse princípio. Por exemplo, gerenciamento incorreto de ponteiros brutos ou referências cíclicas com Rc.



// Vazamento de memória: esqueceu de chamar dropfn leak_memory() {    let ptr = Box::into_raw(Box::new(42));    // ptr não foi liberado — vazamento}


Solução: use Box::from_raw() para liberação correta. Para referências cíclicas, utilize Weak ou Arc.



5. Chamadas FFI inseguras



Chamadas a funções C via FFI (Foreign Function Interface) são uma das principais fontes de vulnerabilidades. Rust não pode controlar a segurança do código externo.



// FFI perigoso: passagem de ponteiro inválidoextern "C" {    fn c_free(ptr: *mut c_void);}

fn free_wrapper(ptr: *mut c_void) { unsafe { c_free(ptr); } // Liberação dupla?}


Solução: use wrappers seguros, verifique os limites dos buffers, aplique std::ffi::CStr para str

Blogs

Book Recommendations