Haszowanie haseł

Aby zapewnić bezpieczeństwo naszym użytkownikom, nie przechowujemy ich haseł w czytelnej postaci, ale przechowujemy tylko ich skrót (tzw. hash). Ze skrótu nie można odtworzyć pierwotnej postaci hasła. Ważne jest, aby użyć bezpiecznego algorytmu do tworzenia skrótu. Pomoże nam w tym klasa Nette\Security\Passwords.

Instalacja i wymagania

Framework automatycznie dodaje do kontenera DI usługę typu Nette\Security\Passwords pod nazwą security.passwords, do której dostaniesz się, prosząc o jej przekazanie za pomocą wstrzykiwania zależności.

use Nette\Security\Passwords;

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

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

Wybieramy, który bezpieczny algorytm do generowania hasha użyć i konfigurujemy jego parametry.

Domyślnie używany jest PASSWORD_DEFAULT, czyli wybór algorytmu pozostawia się PHP. Algorytm może się zmienić w nowszych wersjach PHP, jeśli pojawią się nowsze, silniejsze algorytmy haszujące. Dlatego powinieneś być świadomy, że długość wynikowego hasha może się zmienić, i powinieneś go przechowywać w sposób, który może pomieścić wystarczającą liczbę znaków, 255 to zalecana szerokość.

Przykład ustawienia szybkości haszowania algorytmem bcrypt przez zmianę parametru cost: (w 2020 roku domyślne jest 10, haszowanie hasła trwa około 80ms, dla cost 11 około 160ms, dla cost 12 około 320ms, im wolniej, tym lepsza ochrona, przy czym szybkość 10–12 jest już uważana za ochronę wystarczającą)

// będziemy haszować hasła 2^12 (2^cost) iteracjami algorytmu bcrypt
$passwords = new Passwords(PASSWORD_BCRYPT, ['cost' => 12]);

Za pomocą wstrzykiwania zależności:

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

hash (string $passwords): string

Generuje hash hasła.

$res = $passwords->hash($password); // Haszuje hasło

Wynik $res to ciąg znaków, który oprócz samego hasha zawiera również identyfikator użytego algorytmu, jego ustawienia i sól kryptograficzną (losowe dane zapewniające, że dla tego samego hasła zostanie wygenerowany inny hash). Jest więc wstecznie kompatybilny, gdy na przykład zmienisz parametry, to również hashe zapisane z użyciem poprzednich ustawień będą mogły być zweryfikowane. Cały ten wynik zapisuje się do bazy danych, więc nie ma potrzeby zapisywać soli lub ustawień osobno.

verify (string $password, string $hash)bool

Sprawdza, czy podane hasło odpowiada danemu skrótowi. $hash pobierz z bazy danych według podanej nazwy użytkownika lub adresu e-mail.

if ($passwords->verify($password, $hash)) {
	// poprawne hasło
}

needsRehash (string $hash): bool

Sprawdza, czy hash odpowiada opcjom podanym w konstruktorze.

Przydaje się użyć w momencie, gdy np. zmieniasz szybkość haszowania. Weryfikacja przebiegnie według zapisanych ustawień, a jeśli needsRehash() zwróci true, to trzeba ponownie utworzyć hash, tym razem z nowymi parametrami, i zapisać go ponownie do bazy danych. W ten sposób automatycznie “aktualizują się” zapisane hashe podczas logowania użytkowników.

if ($passwords->needsRehash($hash)) {
	$hash = $passwords->hash($password);
	// zapisać $hash do bazy danych
}
wersja: 4.0