Implementierung der Benutzerauthentifizierung sicher ohne sich auf ein Framework (oder eine Bibliothek eines Drittanbieters, wie OpenID) zu verlassen, ist kein triviales Unterfangen.
Bei einem Überblick über 10.000 Fuß müssen Sie sich entscheiden:
- Haben Sie Benutzernamen, E-Mail-Adressen oder Benutzer-IDs als primären Selektor?
- Wie sollten Sie Kennwörter speichern? PROTIP:
password_hash()
o scrypt sind der richtige Weg.
- Wie sollten Sie mit "Erinnerungs-Kontrollkästchen" umgehen? Dafür gibt es im Internet eine Menge schlechter Strategien. Behandeln Sie jede davon mit Skepsis, denn sie könnten Schwachstellen in Ihre Anwendung einführen.
- Wie soll die Anwendung mit Benutzern umgehen, die ihr Passwort vergessen haben?
Die Informationen in dieser Antwort sind relevant und auf dem Stand vom 9. Mai 2015 und könnten durch den Abschluss des Verfahrens überholt sein. Passwort-Hashing-Wettbewerb
Primäre Selektoren
Im Allgemeinen sind Benutzernamen und E-Mail-Adressen besser als ID-Nummern.
Es sollte keine Sicherheitsanforderung für die Geheimhaltung von Benutzernamen geben, da diese in der Praxis ohnehin durchgesickert sind, wenn jemand versucht, sich zu registrieren.
Sie können entscheiden, ob E-Mail-Adressen als geheim behandelt werden sollen oder nicht. Die Benutzer möchten im Allgemeinen nicht Spammern, Betrügern und Trollen ausgesetzt sein.
Passwort-Hashing
Sie sollten Folgendes verwenden password_hash()
y password_verify()
es sei denn, Sie sind ausreichend erfahren im Schreiben von Kryptographie-Bibliotheken, um darüber hinauszugehen.
Jenseits von Bcrypt
Manchmal werden Entwickler gerne kreativ (z. B. fügen sie einen "Pfeffer" hinzu, was in der Regel Pre-Hashing oder HMACing von Passwörtern mit einem statischen Schlüssel bedeutet) und gehen über die Standardimplementierungen hinaus. Wir selbst haben dies getan, allerdings sehr konservativ.
Für unsere internen Projekte (die ein viel höheres Maß an Sicherheit aufweisen als die Blogs der meisten Leute) haben wir einen Wrapper um diese API geschrieben, der PasswordLock
das ein Kennwort zunächst mit einem Hashwert sha256
kodiert dann die rohe Hash-Ausgabe in base64 und übergibt diesen base64-kodierten Hash an password_hash()
und verschlüsselt schließlich den bcrypt-Hash mit eine ordnungsgemäß implementierte Verschlüsselungsbibliothek .
Um es noch einmal zu wiederholen, Anstatt zu pfeffern, verschlüsseln wir unsere Passwort-Hashes. Dies gibt uns mehr Flexibilität im Falle eines Lecks (wir können entschlüsseln und wieder verschlüsseln, weil wir den Schlüssel kennen). Außerdem können wir unseren Webserver und unsere Datenbank auf separater Hardware im selben Rechenzentrum betreiben, um die Auswirkungen einer SQL-Injection-Schwachstelle abzuschwächen. (Um mit dem Knacken von Hashes beginnen zu können, benötigen Sie den AES-Schlüssel. Sie können ihn nicht von der Datenbank bekommen, selbst wenn Sie in das Dateisystem eindringen).
// Storage:
$stored = \ParagonIE\PasswordLock\PasswordLock::hashAndEncrypt($password, $aesKey);
// Verification:
if (\ParagonIE\PasswordLock\PasswordLock::decryptAndVerify($password, $stored, $aesKey)) {
// Authenticated!
}
Passwortspeicherung mit PasswordLock
:
hash('sha256', $password, true);
base64_encode($step1);
password_hash($step2, PASSWORD_DEFAULT);
Crypto::encrypt($step3, $secretKey);
Passwortüberprüfung mit PasswordLock
:
Crypto::decrypt($ciphertext, $secretKey);
hash('sha256', $password, true);
base64_encode($step2);
password_verify($step3, $step1);
Weitere Lektüre