Login- und Sitzungssicherheit
Die Anmeldeseite ist die Tür zu Ihrer Website; die Sitzung ist der Schlüssel, der die Identität der eingetretenen Person bei jeder weiteren Anfrage mitführt. Ist eines von beiden schwach, können Konten übernommen werden, ganz gleich, wie solide der übrige Code ist. Die verbreiteten Probleme sind bekannt: Passwörter, die mit einem schwachen Verfahren gespeichert sind, unbegrenzte Passwortversuche, eine Sitzungs-ID, die bei der Anmeldung nicht erneuert wird, ungeschützte Cookies und Berechtigungen, die nur im Menü ausgeblendet, auf dem Server aber nicht geprüft werden.
Diese Anleitung erklärt, wie die Anmelde- und Sitzungsschicht einer in PHP geschriebenen Website richtig aufgebaut wird. Zu den Maßnahmen auf Benutzerseite siehe die Anleitung Starke Passwörter und Passwortmanager.
Kurz gefasst
- Passwörter werden mit
password_hashgespeichert; MD5 und SHA-1 sind ungeeignet. - Anmeldeversuche werden pro Konto und pro IP-Adresse begrenzt; die Fehlermeldung bleibt allgemein.
- Bei der Anmeldung wird die Sitzungs-ID erneuert; das Cookie erhält die Flags Secure, HttpOnly und SameSite.
- Die Berechtigung wird bei jeder Anfrage auf dem Server geprüft; das Menü auszublenden genügt nicht.
Auf dieser Seite
Vier Grundlagen
-
Speichern Sie nicht das Passwort, sondern seinen Hash
Passwörter werden in der Datenbank niemals im Klartext oder in einer umkehrbaren Form gespeichert. Auch schnelle Hashfunktionen wie MD5, SHA-1 und SHA-256 ohne Salt sind für die Speicherung von Passwörtern ungeeignet; weil sie schnell sind, lassen sich die Passwörter aus einer abgeflossenen Datenbank in kurzer Zeit durchprobieren. Die PHP-Funktion
password_hashverwendet einen langsamen, für Passwörter entwickelten Algorithmus und erzeugt den Salt von selbst.PHP<?php // Registrierung oder Passwortänderung $karma = password_hash($parola, PASSWORD_DEFAULT); // $karma wird in die Datenbank geschrieben (Spalte: VARCHAR(255)) // Anmeldung if (password_verify($girilenParola, $kullanici['parola_karma'])) { // Hash aktualisieren, wenn sich Algorithmus oder Kostenfaktor geändert haben if (password_needs_rehash($kullanici['parola_karma'], PASSWORD_DEFAULT)) { $yeni = password_hash($girilenParola, PASSWORD_DEFAULT); $pdo->prepare('UPDATE kullanicilar SET parola_karma = ? WHERE id = ?') ->execute([$yeni, $kullanici['id']]); } }
: Vergrößern -
Begrenzen Sie die Anzahl der Versuche
Unbegrenzte Versuche machen das Erraten von Passwörtern möglich. Zählen Sie fehlgeschlagene Versuche sowohl pro Konto als auch pro IP-Adresse; verhängen Sie ab einer bestimmten Anzahl eine Wartezeit und verlängern Sie diese stufenweise. Die Fehlermeldung darf nicht erkennen lassen, ob der Benutzername oder das Passwort falsch war.
: Vergrößern -
Erneuern Sie die Sitzungs-ID bei der Anmeldung
Session-Fixation entsteht, wenn die Sitzungs-ID, die der Benutzer vor der Anmeldung hatte, auch nach der Anmeldung gültig bleibt; wer die ID vorher kennt, kann dieselbe Sitzung nutzen, sobald sich der Benutzer angemeldet hat. Die Lösung ist einfach: Erneuern Sie die Sitzungs-ID, wenn die Anmeldung erfolgreich war und wenn sich die Berechtigungsstufe ändert.
: Vergrößern -
Prüfen Sie die Berechtigung bei jeder Anfrage auf dem Server
Eine Schaltfläche oder einen Menüpunkt auszublenden ist keine Berechtigungsprüfung; jeder, der die Adresse kennt, kann die Anfrage direkt senden. Jede Seite und jede Aktion muss auf dem Server zuerst prüfen, ob die Sitzung gültig ist, und dann, ob der Benutzer berechtigt ist, diese Aktion an genau diesem Datensatz auszuführen.
: Vergrößern
Anzeichen: Woran erkennt man das Problem?
- In der Datenbank: Sehen Sie in der Passwortspalte hexadezimale Werte mit 32 oder 40 Zeichen (MD5, SHA-1) oder lesbare Passwörter, ist das Speicherverfahren schwach. Die Ausgabe von
password_hashbeginnt mit$2y$oder$argon2. - In den Protokollen: Zahlreiche POST-Anfragen an die Anmeldeadresse in kurzer Zeit; aufeinanderfolgende Versuche mit unterschiedlichen Benutzernamen; erfolgreiche Anmeldungen aus ungewöhnlichen Ländern oder zu ungewöhnlichen Uhrzeiten.
- Im Browser: In den Entwicklertools fehlen dem Sitzungs-Cookie die Flags
Secure,HttpOnlyundSameSite; die Sitzungs-ID ist vor und nach der Anmeldung dieselbe. - In der Anwendung: Nach der Abmeldung wird der Inhalt angezeigt, wenn die Adresse einer Administrationsseite direkt eingegeben wird; ändert man die Datensatznummer in der Adresse, öffnet sich der Datensatz eines anderen Benutzers.
Sicherer Anmeldeablauf
Das folgende Beispiel zeigt die Begrenzung der Versuche, die Prüfung des Passworts, bei Bedarf die Aktualisierung des Hashes und die Erneuerung der Sitzungs-ID im Zusammenspiel.
<?php
$eposta = strtolower(trim((string) ($_POST['eposta'] ?? '')));
$parola = (string) ($_POST['parola'] ?? '');
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
if (cokFazlaDeneme($pdo, $eposta, $ip)) {
http_response_code(429);
echo 'Zu viele Versuche. Bitte versuchen Sie es in 15 Minuten erneut.';
return;
}
$sorgu = $pdo->prepare('SELECT id, parola_karma, rol FROM kullanicilar WHERE eposta = ? AND aktif = 1');
$sorgu->execute([$eposta]);
$kullanici = $sorgu->fetch();
// Auch ohne Benutzer eine Prüfung durchführen: Die Antwortzeit soll nicht verraten, ob der Benutzer existiert.
// SAHTE_KARMA: Wert, der einmalig mit password_hash() erzeugt und als Konstante in der Konfiguration abgelegt wird
$karma = $kullanici ? $kullanici['parola_karma'] : SAHTE_KARMA;
$dogru = password_verify($parola, $karma) && $kullanici !== false;
if (!$dogru) {
denemeKaydet($pdo, $eposta, $ip);
echo 'E-Mail-Adresse oder Passwort ist falsch.';
return;
}
session_regenerate_id(true); // gegen Session-Fixation
$_SESSION['kullanici_id'] = (int) $kullanici['id'];
$_SESSION['rol'] = $kullanici['rol'];
$_SESSION['son_islem'] = time();
$_SESSION['csrf'] = bin2hex(random_bytes(32));- Auch wenn der Benutzer nicht gefunden wird, findet eine Hash-Prüfung statt; so lässt sich aus der Antwortzeit nicht ablesen, ob der Benutzer existiert.
- Es gibt nur eine, allgemein gehaltene Fehlermeldung: „E-Mail-Adresse oder Passwort ist falsch.“
- Ziehen Sie eine befristete Wartezeit einer dauerhaften Kontosperre vor; andernfalls kann jemand die Konten der Benutzer durch absichtlich falsche Versuche sperren.
- Das Anmeldeformular muss ein CSRF-Token enthalten.
Für den Zähler der Versuche genügt eine einfache Tabelle:
<?php
// Tabelle: giris_denemeleri (eposta VARCHAR(190), ip VARCHAR(45), zaman DATETIME, INDEX(eposta), INDEX(ip))
function cokFazlaDeneme(PDO $pdo, string $eposta, string $ip): bool
{
$sorgu = $pdo->prepare(
'SELECT COUNT(*) FROM giris_denemeleri
WHERE (eposta = ? OR ip = ?) AND zaman > (NOW() - INTERVAL 15 MINUTE)'
);
$sorgu->execute([$eposta, $ip]);
return (int) $sorgu->fetchColumn() >= 5;
}
function denemeKaydet(PDO $pdo, string $eposta, string $ip): void
{
$pdo->prepare('INSERT INTO giris_denemeleri (eposta, ip, zaman) VALUES (?, ?, NOW())')
->execute([$eposta, $ip]);
}Umstieg von einem alten Hash-Verfahren
Werden die Passwörter auf einer bestehenden Website mit MD5 oder SHA-1 gespeichert, ist der Umstieg möglich, ohne dass die Benutzer ihr Passwort zurücksetzen müssen: Meldet sich ein Benutzer an, wird das Passwort mit dem alten Verfahren geprüft; ist es richtig, wird es im selben Moment mit password_hash neu gehasht und gespeichert. Da das Risiko fortbesteht, solange alte Hashes in der Datenbank liegen, sollte nach einer bestimmten Frist für Konten, die noch nicht umgestellt sind, das Zurücksetzen des Passworts verpflichtend sein.
Sitzungseinstellungen
Legen Sie die Flags des Sitzungs-Cookies und das Verhalten der Sitzung vor dem Aufruf von session_start fest.
<?php
ini_set('session.use_strict_mode', '1'); // IDs ablehnen, die nicht vom Server erzeugt wurden
ini_set('session.use_only_cookies', '1'); // die ID wird nicht in der Adresse übertragen
session_set_cookie_params([
'lifetime' => 0, // endet, wenn der Browser geschlossen wird
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax',
]);
session_start();
// Timeout bei Inaktivität: 30 Minuten
$sure = 30 * 60;
if (isset($_SESSION['son_islem']) && time() - $_SESSION['son_islem'] > $sure) {
$_SESSION = [];
session_destroy();
header('Location: giris?oturum=doldu');
return;
}
$_SESSION['son_islem'] = time();- Secure: Das Cookie wird nur über HTTPS gesendet.
- HttpOnly: JavaScript kann das Cookie nicht auslesen; das erschwert bei XSS den Diebstahl des Cookies.
- SameSite: Schränkt ein, dass das Cookie bei Anfragen mitgesendet wird, die von anderen Websites ausgehen.
- Strikter Modus (strict mode): Lehnt Sitzungs-IDs ab, die nicht vom Server erzeugt wurden.
- Timeout: Beenden Sie eine Sitzung, in der eine bestimmte Zeit lang nichts geschieht; halten Sie die Zeitspanne in Administrationsbereichen kurz.
- Schreiben Sie die Sitzungs-ID niemals in die Adresse (URL).
Zerstören Sie die Sitzung bei der Abmeldung tatsächlich:
<?php
session_start();
$_SESSION = [];
if (ini_get('session.use_cookies')) {
$p = session_get_cookie_params();
setcookie(session_name(), '', [
'expires' => time() - 3600,
'path' => $p['path'],
'domain' => $p['domain'],
'secure' => $p['secure'],
'httponly' => $p['httponly'],
'samesite' => $p['samesite'] ?: 'Lax',
]);
}
session_destroy();
header('Location: giris');Berechtigungsprüfung bei jeder Anfrage
Bündeln Sie die Berechtigungsprüfung in einer gemeinsamen Funktion, die am Anfang jeder Seite aufgerufen wird. Es gibt zwei getrennte Fragen: Darf der Benutzer diese Art von Aktion ausführen (Rolle), und gehört dieser Datensatz ihm (Eigentümerschaft)?
<?php
// Wird am Anfang jeder Administrationsseite aufgerufen
function yetkiIste(string $rol): void
{
if (empty($_SESSION['kullanici_id'])) {
header('Location: giris');
exit;
}
if (($_SESSION['rol'] ?? '') !== $rol) {
http_response_code(403);
echo 'Sie sind nicht berechtigt, diese Seite anzuzeigen.';
exit;
}
}
// Eigentümerschaft des Datensatzes: Die Benutzer-ID aus der Sitzung wird in die Abfrage aufgenommen
$sorgu = $pdo->prepare('SELECT * FROM siparisler WHERE id = ? AND kullanici_id = ?');
$sorgu->execute([(int) ($_GET['id'] ?? 0), $_SESSION['kullanici_id']]);
$siparis = $sorgu->fetch();
if (!$siparis) {
http_response_code(404);
echo 'Die Bestellung wurde nicht gefunden.';
return;
}Vertrauen Sie nicht der Datensatznummer in der Adresse oder im Formular; nehmen Sie immer auch die Benutzer-ID aus der Sitzung in die Abfrage auf. Fehler in der Zugriffskontrolle gehören zu den Risiken ganz oben in den OWASP Top 10.
Schützen Sie den Administrationsbereich mit zusätzlichen Schichten
- Zwei-Faktor-Authentifizierung: Machen Sie sie für Administratorkonten verpflichtend. Zur Benutzerseite siehe die Anleitung Zwei-Faktor-Authentifizierung.
- IP-Beschränkung: Wird der Administrationsbereich nur von der festen IP-Adresse Ihres Büros oder über ein VPN aufgerufen, beschränken Sie das Verzeichnis auf diese IP-Adresse.
- Zusätzliche Passwortschicht: Gibt es keine feste IP-Adresse, lässt sich das Verzeichnis auf Serverebene mit einem zweiten Passwort versehen (HTTP-Basisauthentifizierung).
- Adresse des Administrationsbereichs: Eine nicht leicht zu erratende Adresse verringert das Grundrauschen automatisierter Scans, ist für sich allein aber kein Schutz.
- Persönliche Konten: Verwenden Sie kein gemeinsames „admin“-Konto; jeder Administrator erhält ein eigenes Konto, und die ausgeführten Aktionen werden protokolliert.
# admin/.htaccess : Zugriff auf den Administrationsbereich nur von bestimmten IP-Adressen
# (203.0.113.10 ist eine Beispieladresse; tragen Sie Ihre eigene feste IP-Adresse ein)
Require ip 203.0.113.10
# Ohne feste IP-Adresse: zweite Passwortschicht auf Serverebene
# AuthType Basic
# AuthName "Verwaltung"
# AuthUserFile /home/benutzer/.htpasswd
# Require valid-userPasswort zurücksetzen
- Das Token im Link zum Zurücksetzen muss zufällig (
random_bytes), nur einmal verwendbar und kurzlebig sein; in der Datenbank wird sein Hash gespeichert. - Sagen Sie nicht „Diese E-Mail-Adresse ist nicht registriert“; zeigen Sie in jedem Fall dieselbe Meldung: „Falls die Adresse registriert ist, wurde ein Link zum Zurücksetzen gesendet.“
- Beenden Sie nach einer Passwortänderung die übrigen offenen Sitzungen des Benutzers und senden Sie eine Benachrichtigung per E-Mail.
- Versenden Sie das neue Passwort nicht per E-Mail; der Benutzer legt es selbst fest.
- Stellen Sie in den Passwortregeln die Länge in den Vordergrund; verlangen Sie mindestens 12 Zeichen und lehnen Sie sehr verbreitete Passwörter ab.
Checkliste
- Passwörter werden mit
password_hashgespeichert; für alte Hashes gibt es einen Umstiegsplan. - Anmeldeversuche sind pro Konto und pro IP-Adresse begrenzt; die Fehlermeldung ist allgemein gehalten.
- Nach erfolgreicher Anmeldung wird
session_regenerate_id(true)aufgerufen. - Das Sitzungs-Cookie hat die Flags Secure, HttpOnly und SameSite; der strikte Modus ist aktiv.
- Es gibt ein Timeout bei Inaktivität; die Abmeldung zerstört die Sitzung.
- Jede Seite und jede Aktion prüft auf dem Server Sitzung, Rolle und Eigentümerschaft des Datensatzes.
- Zwei-Faktor-Authentifizierung für Administratorkonten; IP-Beschränkung oder zusätzliche Passwortschicht für den Administrationsbereich.
- Das Token zum Zurücksetzen des Passworts ist nur einmal verwendbar und befristet.
- Erfolgreiche und fehlgeschlagene Anmeldungen werden protokolliert.
Häufige Fragen
Welchen Algorithmus verwendet PASSWORD_DEFAULT?
Die Konstante wählt den für die jeweilige PHP-Version empfohlenen Algorithmus (in aktuellen Versionen bcrypt). Ändert sich der Algorithmus später, wird der Hash mit password_needs_rehash bei der nächsten Anmeldung des Benutzers von selbst aktualisiert. Definieren Sie die Spalte deshalb als VARCHAR(255).
Soll ich dem Passwort einen eigenen Salt hinzufügen?
Nein. password_hash erzeugt für jedes Passwort selbst einen zufälligen Salt und speichert ihn im Hash. Ein manuell hinzugefügter Salt ist nicht nötig.
Ersetzt ein Captcha die Begrenzung der Versuche?
Für sich allein nicht. Ein Captcha erschwert automatisierte Versuche; die Anzahl der Versuche auf dem Server zu begrenzen, bleibt trotzdem notwendig. Beides lässt sich kombinieren.
Ist die Funktion „Angemeldet bleiben“ sicher?
Richtig umgesetzt, ja: Im langlebigen Cookie darf weder die Benutzer-ID noch das Passwort stehen, sondern ein zufälliges Token, dessen Hash in der Datenbank liegt; das Token muss bei jeder Verwendung erneuert und bei einer Passwortänderung widerrufen werden.
BYK Yazılım Support-Team
Diese Anleitung wird vom Support-Team von BYK Yazılım erstellt und regelmäßig überprüft. Letzte Aktualisierung: 04.10.2026.
Verwandte Anleitungen
- CSRF: Was ist das und wie verhindern Sie es?CSRF-Token, SameSite-Cookie, Origin-Prüfung und POST für alle Aktionen, die einen Zustand ändern.
- Was ist die Zwei-Faktor-Authentifizierung und wie aktiviert man sie?Eine zweite Sicherheitsebene für Ihre Konten: Verfahren im Vergleich und der allgemeine Weg bei Google- und Microsoft-Konten.
- Wie erstellt man ein starkes Passwort? Was ist ein Passwortmanager?Lange, nicht wiederverwendete Passwörter, Passphrasen und der richtige Umgang mit einem Passwortmanager.
- XSS: Was ist das und wie verhindern Sie es?Kontextgerechtes Ausgabe-Escaping, Content-Security-Policy, HttpOnly-Cookie und die Bereinigung von Rich Text.
Sehen wir uns Ihre Website gemeinsam an
BYK Yazılım entwickelt Unternehmenswebsites. Schreiben Sie uns, wenn Sie Fragen zu Ihrer Website haben.
Kontakt aufnehmen Unsere Leistung: Unternehmenswebsite