Wenn C++ auf das Web trifft: Warum Sicherheit Ihr größtes Kopfzerbrechen ist
\n\nHaben Sie sich jemals gefragt, warum Hacker C++-Anwendungen so sehr lieben? Nein, nicht weil der Code komplex ist. Sondern weil Entwickler im Streben nach Leistung oft die C++-Sicherheit vergessen. Und dafür mit Benutzerdaten, Reputation und Geld bezahlen.
\n\nStellen Sie sich vor: Sie haben einen coolen Server in C++ geschrieben, der Anfragen blitzschnell verarbeitet. Aber eine einzige nicht bereinigte Eingabe – und ein Angreifer leert die gesamte Datenbank. Oder, noch schlimmer, fügt ein Skript ein, das die Sitzungen aller Website-Besucher stiehlt. Kommt Ihnen das bekannt vor? Wenn nicht – großartig, dann lesen Sie diesen Artikel genau richtig.
\n\nIn diesem Material analysieren wir die beiden gefährlichsten Angriffe auf Webanwendungen – SQL-Injection und Cross-Site-Scripting (XSS) – und zeigen, wie Sie sich speziell in C++ dagegen schützen. Ohne Magie, mit echten Codebeispielen. Los geht's.
\n\nSQL-Injection: Wie Hacker Ihre Abfrage in eine Waffe verwandeln
\n\nSQL-Injection liegt vor, wenn ein Angreifer in ein Eingabefeld (z. B. Login oder Suchanfrage) ein Stück SQL-Code einfügt. Wenn Ihre Anwendung diese Eingabe blind in eine Abfrage einsetzt, führt die Datenbank statt der Benutzersuche etwas wie DROP TABLE users aus. Oder, noch schlimmer, gibt alle Passwörter preis.
Typischer Anfängerfehler (und wie man ihn vermeidet)
\n\nSehen Sie sich diesen Code an. Er sieht harmlos aus, ist aber eine Zeitbombe:
\n\n// GEFÄHRLICH! Machen Sie das niemals\nstd::string username = getUserInput(); // Benutzer gab ein: ' OR '1'='1\nstd::string query = "SELECT * FROM users WHERE username = '" + username + "'";\n// Ergebnis: SELECT * FROM users WHERE username = '' OR '1'='1'\n// Gibt alle Benutzer zurück!\n\nSehen Sie das Problem? Wenn der Benutzer ' OR '1'='1 eingibt, gibt die Abfrage die gesamte Tabelle zurück. Und bei '; DROP TABLE users; -- heißt es goodbye, Datenbank.
Der richtige Ansatz: Parametrisierte Abfragen
\n\nDie einzig zuverlässige Methode zum Schutz vor SQL-Injection in C++ ist die Verwendung parametrisierter Abfragen. Die Datenbank unterscheidet selbst zwischen Code und Daten. So sieht das mit der Bibliothek libpqxx (für PostgreSQL) oder MySQL Connector/C++ aus:
\n\n#include <iostream>\n#include <pqxx/pqxx> // libpqxx für PostgreSQL\n\nvoid safeQuery(const std::string& username) {\n try {\n pqxx::connection conn("dbname=mydb user=myuser password=mypass");\n pqxx::work txn(conn);\n \n // Parametrisierte Abfrage: $1 ist der Parameter\n std::string query = "SELECT * FROM users WHERE username = $1";\n pqxx::result result = txn.exec_params(query, username);\n \n for (auto row : result) {\n std::cout << "User: " << row["username"].c_str() << std::endl;\n }\n txn.commit();\n } catch (const std::exception &e) {\n std::cerr << "Error: " << e.what() << std::endl;\n }\n}\n\nint main() {\n std::string input;\n std::cout << "Enter username: ";\n std::getline(std::cin, input);\n safeQuery(input);\n return 0;\n}\n\nBeachten Sie: Wir verwenden txn.exec_params anstelle von String-Konkatenation. Die Datenbank escaped Sonderzeichen selbst. Selbst wenn der Benutzer ' OR '1'='1 eingibt, wird dies als Zeichenkette und nicht als Teil eines SQL-Befehls interpretiert.
Was tun, wenn Sie rohes SQLite verwenden?
\n\nAuch mit SQLite können Sie sicher arbeiten. Verwenden Sie sqlite3_prepare_v2 und sqlite3_bind_text:
#include <sqlite3.h>\n#include <iostream>\n\nvoid safeSQLiteQuery(sqlite3* db, const std::string& username) {\n sqlite3_stmt* stmt;\n const char* sql = "SELECT * FROM users WHERE username = ?";\n \n if (sqlite3_prepare_v2