Introdução: por que a segurança do código C++ é crítica?
C++ é uma das linguagens mais poderosas e performáticas, mas sua flexibilidade exige alta responsabilidade do desenvolvedor. Ao contrário de muitas linguagens modernas com gerenciamento automático de memória (Java, Python), o C++ fornece acesso direto à memória e aos recursos do sistema. Isso abre amplas possibilidades para ataques: desde estouro de buffer até vazamento de dados.
Para desenvolvedores C++ iniciantes, entender as vulnerabilidades típicas não é apenas teoria, mas uma necessidade. Um erro de algumas linhas pode levar à queda do servidor, vazamento de senhas ou execução de código arbitrário por um invasor. Neste artigo, analisaremos o top 10 das vulnerabilidades mais comuns em C++ com exemplos e formas de proteção.
Top 10 vulnerabilidades C++ com exemplos e proteção
1. Estouro de buffer (Buffer Overflow)
Problema: Gravação de dados além dos limites do array alocado. Este é um clássico do C/C++ que permite sobrescrever variáveis adjacentes, endereço de retorno da função ou dados no heap.
// Exemplo de vulnerabilidade#include <cstring>#include <iostream>
void vulnerable() { char buffer[10]; std::cout << "Digite uma string: "; std::cin >> buffer; // Perigo! Sem verificação de tamanho}
int main() { vulnerable(); return 0;}Consequências: Execução de código arbitrário (RCE), falha do programa.
Proteção: Use std::string, std::vector, funções seguras (por exemplo, strncpy com especificação de tamanho).
// Versão segura#include <string>#include <iostream>
void safe() { std::string input; std::getline(std::cin, input); std::cout << "Você digitou: " << input << std::endl;}2. Vazamento de memória (Memory Leak)
Problema: Memória alocada via new/malloc, mas não liberada via delete/free. Com o tempo, a aplicação "consome" toda a memória RAM.
void leaky() { int* data = new int[1000]; // Esqueceu delete[] data;}Consequências: Negação de serviço (DoS), lentidão do sistema.
Proteção: Use smart pointers (std::unique_ptr, std::shared_ptr), RAII (Resource Acquisition Is Initialization).
#include <memory>void safe() { std::unique_ptr<int[]> data = std::make_unique<int[]>(1000); // A memória será liberada automaticamente ao sair da função}3. Desreferenciamento de ponteiro nulo (Null Pointer Dereference)
Problema: Tentativa de acessar a memória no endereço nullptr.
void process(int* ptr) { *ptr = 42; // Se ptr == nullptr, o programa irá falhar}Consequências: Falha imediata (segmentation fault), DoS.
Proteção: Sempre verifique os ponteiros antes de usar ou use referências.
void safe(int* ptr) { if (ptr) { *ptr = 42; } else { // Tratamento de erro }}4. Estouro de inteiro (Integer Overflow)
Problema: O resultado de uma operação aritmética excede os limites do tipo de dado. Isso pode levar a comportamento imprevisível, especialmente ao trabalhar com índices de arrays.
#include <cstdint>void vulnerable() { uint16_t a = 65535; uint16_t b = 1; uint16_t sum = a + b; // Estouro: 65536 -> 0}Consequências: Erros lógicos, estouro de buffer (se usado para calcular tamanho).
Proteção: Use tipos com tamanho fixo (int32_t, int64_t), verifique