Warum eine selbstgebaute Authentifizierung eine Zeitbombe ist
\n\nFast jeder zweite PHP-Entwickler hat schon einmal ein eigenes Login-System geschrieben. Es scheint einfach: Formular, Login-Prüfung, Session. Aber genau in dieser „einfachen“ Phase scheitern Millionen von Websites. SQL-Injection, Session-Diebstahl, Passwort-Raten – Angriffe, die dein Projekt zur Daten-Schleuder machen.
\n\nIn diesem Artikel zeigen wir dir sichere Authentifizierung in PHP von Grund auf. Keine Magie – nur bewährte Praktiken, die bei Facebook, GitHub und in deinem Lieblings-Framework eingesetzt werden. Du lernst, wie du Passwörter richtig hashst, Sessions vor Abfangen schützt und moderne Mechanismen wie JWT implementierst.
\n\nBereit? Los geht's.
\n\n1. Passwort-Hashing: Warum md5() ein Todesurteil ist
\n\nDie erste Sicherheitsregel: Speichere niemals, wirklich niemals Passwörter im Klartext. Die zweite Regel: Verwende keine veralteten Algorithmen wie MD5 oder SHA1. Sie werden in Mikrosekunden berechnet, und jeder Schüler mit einem Laptop kann dein Passwort in einer Stunde knacken.
\n\nPHP bietet eine eingebaute Lösung – die Funktionen password_hash() und password_verify(). Sie nutzen bcrypt (oder Argon2, wenn PHP ≥ 7.2) und fügen automatisch einen „Salt“ hinzu – eine zufällige Zeichenkette, die jeden Hash einzigartig macht.
Beispiel für korrektes Hashing
\n// Benutzerregistrierung\n$password = $_POST['password'];\n$hash = password_hash($password, PASSWORD_BCRYPT, ['cost' => 12]);\n\n// Speichere $hash in der Datenbank\n// Kein manueller Salt! PHP erledigt alles selbst.\n\n\nPasswort-Prüfung beim Login
\n// Benutzer-Login\n$inputPassword = $_POST['password'];\n$storedHash = 'aus der Datenbank';\n\nif (password_verify($inputPassword, $storedHash)) {\n // Passwort korrekt – Zugriff gewähren\n} else {\n // Passwort falsch\n}\n\n\nBeachte den Parameter cost. Er gibt die „Kosten“ der Hash-Berechnung an. Je höher die Zahl, desto länger braucht ein Angreifer zum Knacken. Für 2024 ist cost = 12 der goldene Mittelweg zwischen Sicherheit und Geschwindigkeit.
2. Sessions: Wie du die Schlüssel zu deinem Haus nicht verlierst
\n\nNach erfolgreichem Login starten wir normalerweise eine Session. Aber Standard-PHP-Sessions haben Schwachstellen: vorhersagbare IDs, Leaks über URLs, Session-Fixation.
\n\nSichere Session-Konfiguration
\n// Ganz am Anfang des Skripts, vor jeglicher HTML-Ausgabe\nini_set('session.use_only_cookies', 1);\nini_set('session.use_strict_mode', 1);\nini_set('session.cookie_httponly', 1);\nini_set('session.cookie_secure', 1); // Nur für HTTPS\nini_set('session.cookie_samesite', 'Lax');\n\nsession_start();\n\n// Session-ID nach Login regenerieren\nif ($login_success) {\n session_regenerate_id(true);\n $_SESSION['user_id'] = $user['id'];\n}\n\n\nWas haben wir gemacht:
\n- \n
- use_only_cookies – verbietet die Übergabe der Session-ID über die URL (damit sie nicht aus einem Link gestohlen wird) \n
- use_strict_mode – blockiert nicht initialisierte Sessions \n
- httponly – verhindert JavaScript-Zugriff auf das Session-Cookie (Schutz vor XSS) \n
- secure – das Cookie wird nur über HTTPS gesendet \n
- samesite – Schutz vor CSRF-Angriffen durch gefälschte standortübergreifende Anfragen \n
Und das Wichtigste: Regeneriere immer die Session-ID nach dem Login. Sonst könnte ein Angreifer dem Benutzer vorher seine eigene Session-ID unterjubeln und das Konto übernehmen.
\n\n3. CSRF-Schutz: Prüfen, ob die Anfrage wirklich von dir kommt
\n\nCSRF (Cross-Site Request Forgery) ist ein Angriff, bei dem ein Benutzer auf einen Link wie /delete-account?id=1 klickt und unwissentlich eine Aktion ausführt. Um das zu verhindern, verwendest du Tokens.
Generierung und Prüfung eines CSRF-Tokens
\n// Token generieren (am Anfang der Session oder beim Laden des Formulars)\nif (empty(