Building secure Rust: auditoria de dependências com cargo-audit

1. Introdução à segurança de dependências no ecossistema Rust

O ecossistema Rust é conhecido por suas garantias de segurança de memória, mas isso não elimina vulnerabilidades em dependências de terceiros. Um estudo do GitHub mostrou que mais de 90% das vulnerabilidades em projetos modernos vêm de dependências indiretas. No Rust, com mais de 150.000 crates no crates.io, o risco é real.

O cargo-audit é a ferramenta oficial do RustSec Working Group para auditoria de dependências. Ela consulta o RustSec Advisory Database — um repositório curado de vulnerabilidades (CVEs), crates retirados (yanked) e código inseguro (unsound) — e compara com as dependências do seu projeto.

// Exemplo conceitual: como o cargo-audit analisa seu Cargo.lock
// (pseudocódigo ilustrativo)
fn main() {
    let dependencias = parse_cargo_lock();
    let vulnerabilidades = rustsec_db::consultar(&dependencias);
    for vuln in vulnerabilidades {
        println!("⚠️  {}: {} ({})", vuln.crate_name, vuln.severity, vuln.cve_id);
    }
}

2. Instalação e configuração inicial do cargo-audit

A instalação é simples:

cargo install cargo-audit

Para manter a versão atualizada, recomenda-se usar cargo install --force cargo-audit periodicamente ou adicionar ao seu gerenciador de pacotes do sistema.

Configuração básica:

Crie .cargo/audit.toml no diretório do projeto:

[advisories]
ignore = []  # Lista de advisories para ignorar (ex: "RUSTSEC-2023-0001")
severity_threshold = "low"  # Ignora abaixo de "low"

E .cargo/advisories.toml para configurações avançadas:

[advisory_ids]
ignore = ["RUSTSEC-2020-0071"]  # Ignora advisory específico

[severity]
deny = ["critical", "high"]  # Falha em build para critical/high

Primeira execução:

cargo audit

A saída típica mostra:

    Fetching advisory database from https://github.com/RustSec/advisory-db.git
    Scanning Cargo.lock for vulnerabilities (30 dependencies)
    ============ Found 2 vulnerabilities ============
    ID: RUSTSEC-2023-0001
    Crate: example-crate 1.2.3
    Severity: HIGH (7.5)
    Title: Buffer overflow in example-crate
    ...

3. Compreendendo os tipos de vulnerabilidades reportadas

O RustSec Advisory Database classifica advisories em quatro categorias:

Categoria Descrição Exemplo
Security Vulnerabilidade de segurança confirmada CVE-2023-XXXXX
Yanked Crate retirado do crates.io (geralmente por bug crítico) cargo yank
Unsound Código unsafe que viola garantias de segurança Uso incorreto de std::mem::transmute
Notice Aviso geral (ex: fim de suporte de versão) Depreciação de API

Severidade CVSS:

// Simulação de categorização de severidade
enum Severity {
    Critical(f64), // >= 9.0
    High(f64),     // 7.0 - 8.9
    Medium(f64),   // 4.0 - 6.9
    Low(f64),      // 0.1 - 3.9
    None,          // 0.0
}

Exemplo prático de saída real:

ID: RUSTSEC-2023-0062
Package: openssl-src 111.25.3+1.1.1t
Type: unsound
Title: openssl-src contains multiple unsoundness issues in C code
Severity: HIGH (7.5)
Versões afetadas: >= 111.25.0, < 111.25.4
Patched: >= 111.25.4

4. Estratégias de mitigação e remediação

Atualização segura:

# Atualiza dependências de forma segura
cargo update -p crate-vulneravel

# Verifica se a vulnerabilidade foi corrigida
cargo audit

Correção automática (experimental):

cargo audit fix

Esta ferramenta tenta atualizar automaticamente as dependências vulneráveis para versões corrigidas.

Isolamento com cargo-deny:

cargo install cargo-deny
cargo deny init

Configure deny.toml:

[advisories]
vulnerability = "deny"
unsound = "deny"
yanked = "deny"
notice = "warn"

[licenses]
allow = ["MIT", "Apache-2.0", "BSD-3-Clause"]

Verificação com cargo-vet (Mozilla):

cargo install cargo-vet
cargo vet init
cargo vet

cargo-vet verifica se cada dependência foi auditada por uma entidade confiável (Mozilla, Google, etc.) ou se você precisa auditar manualmente.

5. Integração contínua e automação de auditoria

GitHub Actions:

# .github/workflows/audit.yml
name: Security audit
on:
  push:
    branches: [main]
  schedule:
    - cron: '0 0 * * 0'  # Semanal

jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions-rs/audit-check@v1
        with:
          token: ${{ secrets.GITHUB_TOKEN }}

GitLab CI:

# .gitlab-ci.yml
security-audit:
  stage: test
  script:
    - cargo install cargo-audit
    - cargo audit --deny warnings
  only:
    - main
    - tags

Configuração para falhar em build:

# Falha se encontrar qualquer vulnerabilidade
cargo audit --deny warnings

# Falha apenas para critical/high
cargo audit --deny warnings --severity-threshold high

6. Boas práticas avançadas de auditoria

Saída JSON para processamento programático:

cargo audit --json > audit-report.json

Processe com Python ou Rust:

use serde_json::Value;
use std::fs;

fn main() {
    let data: Value = serde_json::from_str(
        &fs::read_to_string("audit-report.json").unwrap()
    ).unwrap();

    if let Some(vulnerabilities) = data["vulnerabilities"]["found"].as_array() {
        for vuln in vulnerabilities {
            println!("CVE: {}", vuln["advisory"]["id"]);
        }
    }
}

Políticas personalizadas com cargo-deny:

[advisories]
ignore = ["RUSTSEC-2023-0001"]  # Falso positivo conhecido

[licenses]
deny = ["GPL-3.0"]  # Empresa não permite GPL

[sources]
allow-git = ["https://github.com/meu-projeto/*"]

Auditoria de dependências transitivas:

# Visualiza árvore de dependências
cargo tree --invert -p crate-vulneravel

# Verifica apenas dependências diretas
cargo audit --direct

7. Casos reais e lições aprendidas

Caso 1: Cargo RCE (2022)
Uma vulnerabilidade no próprio cargo permitia execução remota de código ao baixar crates maliciosos. O advisory RUSTSEC-2022-0014 foi emitido e corrigido em versões posteriores.

Caso 2: libp2p DoS (2023)
A biblioteca de rede P2P libp2p teve uma vulnerabilidade de negação de serviço (RUSTSEC-2023-0036) que afetava todas as versões até 0.52.0.

Caso 3: OpenSSL bindings
Diversos advisories para openssl-src (vulnerabilidades herdadas do C) são comuns. A lição: sempre audite bindings de bibliotecas C.

Erros comuns:

  1. Ignorar advisories sem investigação adequada
  2. Não atualizar a base de advisories (cargo audit faz automaticamente)
  3. Confundir unsound com security (unsound pode ser usado internamente sem risco)
  4. Não auditar dependências de desenvolvimento ([dev-dependencies])

8. Conclusão e próximos passos

Checklist de segurança para Rust em produção:

  • [ ] cargo audit integrado no CI/CD
  • [ ] cargo deny configurado com políticas de licenças
  • [ ] cargo vet para auditoria de dependências críticas
  • [ ] Revisão periódica dos advisories ignorados
  • [ ] Manutenção de versões atualizadas (cargo update semanal)

Ferramentas complementares:

Ferramenta Propósito
cargo-crev Sistema de revisão por pares de dependências
cargo-geiger Detecta uso de unsafe em dependências
cargo-spellcheck Verifica erros de digitação em nomes de crates (typosquatting)

Recursos para aprofundamento:
- RustSec Working Group (WG) — mantenedores do cargo-audit
- RustSec Advisory Database — repositório oficial de advisories
- OWASP Top 10 for Rust — guia de segurança específico para Rust

Referências