Segurança de aplicações C++: 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 C++: top 10 vulnerabilidades na prática



C++ é uma linguagem poderosa e performática, mas sua flexibilidade exige alta responsabilidade do desenvolvedor. Erros no gerenciamento de memória, trabalho com threads ou entrada/saída podem levar a vulnerabilidades graves. Neste artigo, analisaremos as 10 principais vulnerabilidades do C++ com exemplos práticos de código e formas de preveni-las. O material será útil tanto para iniciantes quanto para desenvolvedores experientes que desejam fortalecer a segurança de seus projetos.



1. Estouro de buffer (Buffer Overflow)

Vulnerabilidade clássica que ocorre ao escrever dados além dos limites de um array alocado. Em C++, é especialmente perigosa ao trabalhar com arrays brutos e funções C.



#include <iostream>#include <cstring>

void vulnerable(char* input) { char buffer[10]; strcpy(buffer, input); // PERIGOSO: sem verificação de tamanho std::cout << "Buffer: " << buffer << std::endl;}

int main() { char longInput[] = "AAAAAAAABBBBBBBBCCCCCCCC"; // 24 caracteres vulnerable(longInput); return 0;}


Solução: Use std::string ou strncpy com verificação explícita de tamanho. Em C++ moderno, prefira contêineres STL.



void safe(const std::string& input) {    std::string buffer = input.substr(0, 9);  // cópia segura    std::cout << "Buffer: " << buffer << std::endl;}


2. Vazamentos de memória (Memory Leaks)

Vazamentos ocorrem quando a memória alocada dinamicamente não é liberada. Em aplicações de longa execução, isso leva ao esgotamento de recursos.



void leakExample() {    int* data = new int[1000];  // alocamos memória    // ... trabalho com dados ...    // esquecemos delete[] data; — vazamento!}


Solução: Use ponteiros inteligentes (std::unique_ptr, std::shared_ptr) ou contêineres STL.



void safeExample() {    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)

Tentar acessar a memória no endereço nullptr causa comportamento indefinido e frequentemente leva à falha do programa.



void process(int* ptr) {    *ptr = 42;  // PERIGOSO: se ptr == nullptr}

int main() { int* p = nullptr; process(p); // falha}


Solução: Sempre verifique os ponteiros antes de usar. Use referências se o valor não puder ser nulo.



void safeProcess(int* ptr) {    if (ptr == nullptr) {        throw std::invalid_argument("Ponteiro nulo recebido");    }    *ptr = 42;}


4. Condição de corrida (Race Condition)

Ocorre quando múltiplas threads acessam dados compartilhados simultaneamente sem sincronização.



#include <thread>int counter = 0;

void increment() { for (int i = 0; i < 100000; ++i) { counter++; // operação não atômica — condição de corrida }}

int main() { std::thread t1(increment); std::thread t2(increment); t1.join(); t2.join(); std::cout << "Counter: " << counter; // resultado imprevisível}


Solução: Use mutexes ou operações atômicas.



#include <atomic>std::atomic<int> counter{0};

void safeIncrement() { for (int i = 0; i < 100000; ++i) { counter.fetch_add(1); // operação atômica }}


5. Uso de variáveis não inicializadas

Variáveis não inicializadas contêm "lixo", o que pode levar a comportamento imprevisível.



int main() {    in                

Blogs

Book Recommendations