Einleitung: Warum sichere Authentifizierung keine Option, sondern eine Notwendigkeit ist
Freunde, stellt euch folgendes Szenario vor: Ihr habt eine coole C++-Anwendung geschrieben – einen Chat-Server, eine API für einen Online-Shop oder sogar eine einfache Kundendatenbank. Alles funktioniert, die Benutzer sind zufrieden. Und dann – peng! – jemand stiehlt die Datenbank mit den Passwörtern. Datenleck im Netz, der Ruf ist ruiniert, und die Benutzer sind in Panik. Kommt euch bekannt vor? Leider ist das die Geschichte von Tausenden von Startups und Giganten. Und das alles, weil die sichere Authentifizierung in C++-Anwendungen nur "auf die Schnelle" implementiert wurde.
In diesem Artikel werden wir keine langweiligen Vorträge halten. Wir werden besprechen, wie man den Benutzer-Login in Ihrem C++-Projekt richtig schützt. Sie erfahren, warum es eine Todsünde ist, Passwörter im Klartext zu speichern, wie man Hashing richtig einsetzt und wie man sich vor den häufigsten Angriffen schützt. Los geht's!
Grundlagen der Sicherheit: Die drei Säulen, auf denen alles basiert
Bevor wir Code schreiben, lassen Sie uns klären, was "sichere Authentifizierung" überhaupt bedeutet. Es ist nicht einfach "Login und Passwort prüfen". Es ist eine ganze Philosophie, die aus drei Hauptprinzipien besteht:
- Speichere Passwörter niemals im Klartext. Selbst wenn ein Hacker die Datenbank stiehlt, sollte er nur eine nutzlose Zeichenfolge erhalten.
- Verwende "Salt". Gleiche Passwörter verschiedener Benutzer sollten unterschiedliche Hashes ergeben. Das macht Rainbow-Tabellen unwirksam.
- Schütze den Übertragungskanal. Das Passwort sollte nicht im Klartext über das Netzwerk reisen. Verwenden Sie HTTPS oder Verschlüsselung auf Protokollebene.
Kommen wir nun zur Praxis. Wir werden ein Benutzerauthentifizierungssystem in C++ mit modernen kryptografischen Bibliotheken aufbauen.
Schritt 1: Passwort-Hashing – Den richtigen Algorithmus wählen
Vergessen Sie MD5 und SHA-1. Das ist Schnee von gestern. Für die sichere Speicherung von Passwörtern in C++ werden langsame, angriffsresistente Algorithmen benötigt: bcrypt, scrypt oder Argon2 (letzterer ist der Gewinner des PHC-Wettbewerbs).
Wir werden bcrypt verwenden – es ist einfach, zuverlässig und es gibt eine hervorragende Bibliothek libbcrypt oder bcrypt-cpp. Installieren Sie sie über Ihren Paketmanager (vcpkg, conan oder bauen Sie sie manuell).
Beispiel: Passwort-Hashing mit bcrypt
#include <iostream>#include <string>#include <bcrypt/bcrypt.h> // angenommen, diese Struktur existiert
// Funktion zum Hashen eines Passwortsstd::string hashPassword(const std::string& password) { // Generiere "Salt" (normalerweise macht bcrypt das automatisch) char salt[BCRYPT_HASHSIZE]; char hash[BCRYPT_HASHSIZE]; // Salt-Generierung (die tatsächliche Funktion kann abweichen) bcrypt_gensalt(12, salt); // 12 Runden – ein guter Kompromiss zwischen Geschwindigkeit und Sicherheit // Passwort hashen bcrypt_hashpw(password.c_str(), salt, hash); return std::string(hash);}
int main() { std::string userPassword = "MySuperP@ssw0rd!"; std::string hashed = hashPassword(userPassword); std::cout << "Passwort-Hash: " << hashed << std::endl; return 0;}Beachten Sie: Das Salt ist bereits im Hash integriert. bcrypt generiert automatisch ein eindeutiges Salt für jedes Passwort. Das ist der Schutz vor Brute-Force-Angriffen mit Rainbow-Tabellen.
Passwort-Überprüfung beim Login
Wenn der Benutzer ein Passwort eingibt, können wir es nicht "enthashen" (Hash ist eine Einwegfunktion). Stattdessen vergleichen wir den Hash des eingegebenen Passworts mit dem in der Datenbank gespeicherten:
bool verifyPassword(const std::string& password, const std::string& storedHash) { // bcrypt_checkpw gibt 0 zurück, wenn das Passwort übereinstimmt return (bcrypt_checkpw(password.c_str(), storedHash.c_str()) == 0);}
// Beispiel zur Verwendung im Authentifizierungscodestd::string userInput = "MySuperP@ssw0rd!";