Passwort-Hashing

Um die Sicherheit unserer Benutzer zu gewährleisten, speichern wir ihre Passwörter niemals in lesbarer Form, sondern nur ihren Abdruck (den sogenannten Hash). Aus dem Hash lässt sich das ursprüngliche Passwort nicht zurückrechnen. Wichtig ist, zum Erzeugen des Hashes einen sicheren Algorithmus zu verwenden. Dabei hilft uns die Klasse Nette\Security\Passwords.

Installation und Anforderungen

Das Framework fügt dem DI-Container automatisch einen Service vom Typ Nette\Security\Passwords unter dem Namen security.passwords hinzu. Sie bekommen ihn, indem Sie ihn sich per Dependency Injection übergeben lassen.

use Nette\Security\Passwords;

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

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

Wir wählen, welchen sicheren Algorithmus wir zum Erzeugen des Hashes verwenden, und konfigurieren seine Parameter.

Der Standardwert ist PASSWORD_DEFAULT, die Wahl des Algorithmus bleibt also PHP überlassen. Der Algorithmus kann sich in neueren PHP-Versionen ändern, wenn neuere, stärkere Hashing-Algorithmen erscheinen. Deshalb sollten Sie sich bewusst sein, dass sich die Länge des entstehenden Hashes ändern kann, und ihn so speichern, dass genügend Zeichen Platz haben; empfohlen wird eine Breite von 255.

Beispiel für das Einstellen der Hashing-Geschwindigkeit des Algorithmus bcrypt über den Parameter cost: (2020 ist der Standardwert 10, das Hashen eines Passworts dauert etwa 80 ms; bei cost 11 sind es ca. 160 ms, bei cost 12 ca. 320 ms; je langsamer, desto besser der Schutz, wobei eine Geschwindigkeit von 10–12 bereits als ausreichender Schutz gilt)

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

Mit Dependency Injection:

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

static bcrypt (?int $cost=null): Passwords

Erzeugt eine für den Algorithmus bcrypt konfigurierte Instanz. Der Parameter $cost setzt die oben beschriebene Hashing-Geschwindigkeit; lassen Sie ihn weg, wird der Standardwert von PHP verwendet.

$passwords = Passwords::bcrypt(12);

static argon2id (?int $memoryCost=null, ?int $timeCost=null, ?int $threads=null): Passwords

Erzeugt eine für den Algorithmus Argon2id konfigurierte Instanz. Weggelassene Parameter bleiben den Standardwerten von PHP überlassen. Wurde PHP ohne Unterstützung für Argon2 gebaut, wirft die Methode eine Nette\NotSupportedException.

$passwords = Passwords::argon2id(memoryCost: 1 << 17, timeCost: 4);

hash (string $password): string

Erzeugt den Hash des Passworts.

$res = $passwords->hash($password); // Hasht das Passwort

Das Ergebnis $res ist ein String, der außer dem eigentlichen Hash den Bezeichner des verwendeten Algorithmus, dessen Einstellungen und ein kryptografisches Salt enthält (zufällige Daten, die dafür sorgen, dass für dasselbe Passwort ein anderer Hash entsteht). Er ist deshalb rückwärtskompatibel; ändern Sie zum Beispiel die Parameter, lassen sich mit früheren Einstellungen gespeicherte Hashes weiterhin prüfen. Dieses gesamte Ergebnis wird in der Datenbank gespeichert, das Salt oder die Einstellungen müssen also nicht getrennt gespeichert werden.

verify (string $password, string $hash)bool

Stellt fest, ob das angegebene Passwort zum angegebenen Hash passt. $hash holen Sie anhand des eingegebenen Benutzernamens oder der E-Mail-Adresse aus der Datenbank.

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

needsRehash (string $hash)bool

Stellt fest, ob der Hash zu den im Konstruktor angegebenen Optionen passt.

Es ist sinnvoll, sie zu verwenden, wenn Sie zum Beispiel den cost-Parameter des Hashings ändern. Die Prüfung erfolgt nach den gespeicherten Einstellungen, und gibt needsRehash() true zurück, muss der Hash erneut erzeugt werden, diesmal mit den neuen Parametern, und wieder in der Datenbank gespeichert werden. So werden gespeicherte Hashes bei der Anmeldung der Benutzer automatisch “aufgewertet”.

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