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

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
```html

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



Rust é posicionado como uma linguagem de sistema segura que previne classes inteiras de vulnerabilidades em tempo de compilação. No entanto, isso não significa que aplicações Rust sejam absolutamente invulneráveis. Desenvolvedores iniciantes frequentemente cometem erros que podem levar a sérios problemas de segurança. Neste artigo, vamos analisar as top 10 vulnerabilidades em aplicações Rust que todo iniciante deve conhecer.



1. Uso incorreto de código unsafe



Blocos unsafe são a causa mais comum de vulnerabilidades em Rust. Eles desativam as verificações de segurança, o que pode levar ao desreferenciamento de ponteiros nulos, condições de corrida e corrupção de memória.



// Exemplo perigosounsafe {    let ptr = std::ptr::null::<i32>();    println!("{}", *ptr); // UB! Segmentation fault}

// Versão segurafn safe_access(ptr: *const i32) -> Option<i32> { if ptr.is_null() { return None; } unsafe { Some(*ptr) }}


Recomendação: Minimize o uso de unsafe. Se for necessário, isole-o em funções pequenas e documente cuidadosamente os invariantes.



2. Condições de corrida através de Send e Sync



Rust protege contra condições de corrida através do sistema de ownership, mas a implementação incorreta das traits Send e Sync pode quebrar essa proteção.



use std::cell::UnsafeCell;use std::sync::Arc;

struct UnsafeCounter(UnsafeCell<u32>);

// Implementação perigosaunsafe impl Send for UnsafeCounter {}unsafe impl Sync for UnsafeCounter {}

fn main() { let counter = Arc::new(UnsafeCounter(UnsafeCell::new(0))); let mut handles = vec![]; for _ in 0..10 { let c = counter.clone(); handles.push(std::thread::spawn(move || { // Condição de corrida! unsafe { *c.0.get() += 1; } })); }}


Recomendação: Use Arc<Mutex<T>> ou Arc<RwLock<T>> em vez de implementar sincronização manualmente.



3. Desserialização insegura de dados



Ao desserializar dados de fontes externas (JSON, YAML, bincode), um atacante pode fornecer um payload especialmente criado.



use serde::Deserialize;

#[derive(Deserialize)]struct Config { path: String, buffer_size: usize,}

fn load_config(data: &str) -> Result<Config, serde_json::Error> { // Vulnerabilidade potencial: números muito grandes let config: Config = serde_json::from_str(data)?; if config.buffer_size > 1_000_000 { return Err(serde_json::Error::custom("Buffer too large")); } Ok(config)}


Recomendação: Sempre verifique os limites dos valores após a desserialização. Use #[serde(deserialize_with = "...")] para validadores personalizados.



4. Vazamentos de memória através de Box<dyn Error>



Retornar frequentemente Box<dyn Error> pode levar a vazamentos de memória, especialmente ao trabalhar com grandes volumes de dados.



// Abordagem problemáticafn process_data(data: &[u8]) -> Result<(), Box<dyn std::error::Error>> {    // ... processamento    Ok(())}

// Melhor abordagem#[derive(Debug)]enum AppError { InvalidData(String), IoError(std::io::Error),}

fn process_data_safe(data: &[u8]) -> Result<(), AppError> { // ... processamento Ok(())}


Recomendação: Crie seus próprios tipos de erro usando thiserror ou anyhow para melhor desempenho e segurança.



5. Estouro de buffer em FFI



Ao interagir com código C através de FFI (Foreign Function Interface), é fácil cometer

```

Blogs

Book Recommendations