Sicherheit von C++-Anwendungen: Top-10 Schwachstellen und wie man sie vermeidet

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Sicherheit von C++-Anwendungen: Top-10 Schwachstellen und Schutzmethoden



C++ ist eine leistungsstarke und flexible Programmiersprache, die zur Erstellung von Hochleistungssystemen verwendet wird, von Spielen über Finanzsoftware bis hin zu Betriebssystemen. Diese Leistungsfähigkeit geht jedoch mit Verantwortung einher: Der Entwickler verwaltet den Speicher selbst, was den Weg für zahlreiche Schwachstellen ebnet. Laut OWASP und CWE machen Fehler in C++-Code einen erheblichen Teil der kritischen Sicherheitslücken in Software aus.



In diesem Artikel analysieren wir die Top-10 der gefährlichsten C++-Schwachstellen, zeigen Beispiele für anfälligen Code und geben praktische Ratschläge zu deren Vermeidung. Das Material ist sowohl für Anfänger als auch für erfahrene Entwickler nützlich, die zuverlässigen und sicheren Code schreiben möchten.



1. Pufferüberlauf (Buffer Overflow)



Dies ist eine klassische und eine der gefährlichsten Schwachstellen. Sie tritt auf, wenn ein Programm Daten über die Grenzen des zugewiesenen Puffers hinaus schreibt. Ein Angreifer kann benachbarte Speicherbereiche (Rückkehradresse, Daten) überschreiben und die Kontrolle über die Ausführung erlangen.



Anfälliges Beispiel:

#include <iostream>#include <cstring>

void vulnerable_function(const char* input) { char buffer[10]; strcpy(buffer, input); // Keine Längenprüfung! std::cout << buffer << std::endl;}

int main() { vulnerable_function("AAAAAAAAAAAAAAAAAAAA"); // Pufferüberlauf return 0;}


So schützen Sie sich:

  • Verwenden Sie sichere Alternativen: strncpy, snprintf, std::string.
  • Überprüfen Sie die Länge der Eingabedaten vor dem Kopieren.
  • Aktivieren Sie Compiler-Flags: -fstack-protector-strong (GCC/Clang) und /GS (MSVC).
  • Verwenden Sie Sanitizer: -fsanitize=address zur Erkennung von Speicherfehlern.


2. Speicherlecks (Memory Leaks)



Ein Speicherleck tritt auf, wenn dynamisch zugewiesener Speicher nicht freigegeben wird. Mit der Zeit führt dies zur Speichererschöpfung, Dienstverweigerung (DoS) und instabilem Anwendungsverhalten.



Anfälliges Beispiel:

void leak_memory() {    int* data = new int[1000]; // Speicher zuweisen    // ... mit data arbeiten ...    // delete[] data; vergessen}


So schützen Sie sich:

  • Verwenden Sie intelligente Zeiger: std::unique_ptr, std::shared_ptr, std::vector.
  • Wenden Sie RAII an (Resource Acquisition Is Initialization).
  • Nutzen Sie regelmäßig Analysetools: Valgrind, AddressSanitizer, Dr. Memory.


// Sichere Version mit intelligentem Zeiger#include <memory>void safe_function() {    auto data = std::make_unique<int[]>(1000);    // Speicher wird automatisch freigegeben, wenn der Gültigkeitsbereich verlassen wird}


3. Datenrennen (Data Race) und Wettlaufsituation (Race Condition)



Treten auf, wenn mehrere Threads gleichzeitig ohne Synchronisation auf gemeinsame Daten zugreifen. Sie führen zu unvorhersehbarem Verhalten, Datenbeschädigung und schwer zu findenden Fehlern.



Anfälliges Beispiel:

#include <thread>#include <iostream>

int counter = 0; // Gemeinsame Variable

void increment() { for (int i = 0; i < 100000; ++i) { counter++; // Nicht-atomare Operation }}

int main() { std::thread t1(increment); std::thread t2(increment); t1.join(); t2.join(); std::cout << "Counter: " << counter << std::endl; // Ergebnis unvorhersehbar return 0;}


So schützen Sie sich: