Passwort-Hashing

Um die Sicherheit unserer Benutzer zu gewährleisten, speichern wir ihre Passwörter nie im Klartext, sondern nur als Hash. Das Hashing ist kein umkehrbarer Vorgang, das Kennwort kann nicht wiederhergestellt werden. Das Passwort kann jedoch geknackt werden, und um das Knacken so schwer wie möglich zu machen, müssen wir einen sicheren Algorithmus verwenden. Die Klasse Nette\Security\Passwords wird uns dabei helfen.

Installation und Anforderungen

Das Framework fügt dem DI-Container automatisch einen Dienst Nette\Security\Passwords unter dem Namen security.passwords hinzu, den man durch Übergabe mittels Dependency Injection erhält:

use Nette\Security\Passwords;

class Foo
{
	public function __construct(
		private Passwords $passwords,
	) {
	}
}

__construct($algo=PASSWORD_DEFAULT, array $options=[])string

Wählt aus, welcher sichere Algorithmus für das Hashing verwendet wird und wie er konfiguriert werden soll.

Die Vorgabe ist PASSWORD_DEFAULT, so dass die Wahl des Algorithmus PHP überlassen wird. Der Algorithmus kann sich in neueren PHP-Versionen ändern, wenn neuere, stärkere Hashing-Algorithmen unterstützt werden. Sie sollten sich daher bewusst sein, dass sich die Länge des resultierenden Hashes ändern kann. Daher sollten Sie den resultierenden Hash in einer Weise speichern, die genügend Zeichen speichern kann, 255 ist die empfohlene Breite.

So würden Sie den bcrypt-Algorithmus verwenden und die Hash-Geschwindigkeit mit dem Parameter cost von der Standardeinstellung 10 ändern. Im Jahr 2020 dauert das Hashing eines Kennworts mit Kosten 10 etwa 80 ms, mit Kosten 11 160 ms und mit Kosten 12 320 ms, die Skala ist logarithmisch. Je langsamer, desto besser, Kosten 10–12 werden als langsam genug für die meisten Anwendungsfälle angesehen:

// Wir werden Passwörter mit 2^12 (2^cost) Iterationen des bcrypt-Algorithmus hashen
$passwords = new Passwords(PASSWORD_BCRYPT, ['cost' => 12]);

Mit Dependency Injection:

services:
	security.passwords: Nette\Security\Passwords(::PASSWORD_BCRYPT, [cost: 12])

hash(string $passwords): string

Erzeugt den Hash des Passworts.

$res = $passwords->hash($password); // Hashes des Passworts

Das Ergebnis $res ist eine Zeichenkette, die neben dem Hash selbst auch die Kennung des verwendeten Algorithmus, seine Einstellungen und das kryptografische Salt (Zufallsdaten, die sicherstellen, dass für dasselbe Kennwort ein anderer Hash erzeugt wird) enthält. Es ist daher rückwärtskompatibel, d. h., wenn Sie die Parameter ändern, können die mit den vorherigen Einstellungen gespeicherten Hashes überprüft werden. Das gesamte Ergebnis wird in der Datenbank gespeichert, so dass es nicht notwendig ist, Salt oder Einstellungen separat zu speichern.

verify(string $password, string $hash)bool

Findet heraus, ob das angegebene Passwort mit dem angegebenen Hash übereinstimmt. Holt die $hash aus der Datenbank nach Benutzernamen oder E-Mail Adresse.

if ($passwords->verify($password, $hash)) {
	// Richtiges Passwort
}

needsRehash(string $hash): bool

Findet heraus, ob der Hash mit den im Konstruktor angegebenen Optionen übereinstimmt.

Verwenden Sie diese Methode, wenn Sie zum Beispiel Hash-Parameter ändern. Die Passwortüberprüfung verwendet die mit dem Hash gespeicherten Parameter, und wenn needsRehash() true zurückgibt, müssen Sie den Hash erneut berechnen, diesmal mit den aktualisierten Parametern, und ihn erneut in der Datenbank speichern. Dadurch wird sichergestellt, dass die Hashes der Passwörter automatisch “aktualisiert” werden, wenn sich die Benutzer anmelden.

if ($passwords->needsRehash($hash)) {
	$hash = $passwords->hash($password);
	// $hash in der Datenbank speichern
}
Version: 4.0