Hashing delle password

Per garantire la sicurezza dei nostri utenti non salviamo mai le loro password in forma leggibile, ma solo la loro impronta (il cosiddetto hash). Dall'hash non si può risalire alla password originale. È importante usare un algoritmo sicuro per creare l'hash. In questo ci aiuta la classe Nette\Security\Passwords.

Installazione e requisiti

Il framework aggiunge automaticamente al container DI un servizio di tipo Nette\Security\Passwords con il nome security.passwords. Potete ottenerlo facendovelo passare con la dependency injection.

use Nette\Security\Passwords;

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

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

Scegliamo quale algoritmo sicuro usare per generare l'hash e ne configuriamo i parametri.

Quello predefinito è PASSWORD_DEFAULT, cioè la scelta dell'algoritmo è lasciata a PHP. L'algoritmo può cambiare nelle versioni più recenti di PHP, se compaiono algoritmi di hashing più nuovi e robusti. Dovreste perciò tenere presente che la lunghezza dell'hash risultante può cambiare e salvarlo in un modo che possa contenere abbastanza caratteri; la larghezza consigliata è 255.

Esempio di impostazione della velocità di hashing per l'algoritmo bcrypt cambiando il parametro cost: (nel 2020 il valore predefinito è 10, l'hashing di una password richiede circa 80 ms; con cost 11 circa 160 ms; con cost 12 circa 320 ms; più è lento, migliore è la protezione, e con velocità 10–12 la protezione è già considerata sufficiente)

// hasheremo le password con 2^12 (2^cost) iterazioni dell'algoritmo bcrypt
$passwords = new Passwords(PASSWORD_BCRYPT, ['cost' => 12]);

Con la dependency injection:

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

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

Crea un'istanza configurata per l'algoritmo bcrypt. Il parametro $cost imposta la velocità di hashing descritta sopra; se lo omettete, viene usato il valore predefinito di PHP.

$passwords = Passwords::bcrypt(12);

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

Crea un'istanza configurata per l'algoritmo Argon2id. I parametri omessi restano ai valori predefiniti di PHP. Se PHP è stato compilato senza il supporto per Argon2, il metodo lancia Nette\NotSupportedException.

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

hash (string $password): string

Genera l'hash della password.

$res = $passwords->hash($password); // esegue l'hash della password

Il risultato $res è una stringa che, oltre all'hash stesso, contiene l'identificatore dell'algoritmo usato, le sue impostazioni e un sale crittografico (dati casuali che garantiscono che per la stessa password venga generato un hash diverso). È quindi retrocompatibile: se per esempio cambiate i parametri, gli hash salvati con le impostazioni precedenti si possono comunque verificare. Tutto questo risultato si salva nel database, quindi non serve salvare separatamente il sale o le impostazioni.

verify (string $password, string $hash)bool

Scopre se la password indicata corrisponde all'hash indicato. $hash lo ottenete dal database in base al nome utente o all'indirizzo email inserito.

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

needsRehash (string $hash)bool

Scopre se l'hash corrisponde alle opzioni indicate nel costruttore.

Torna utile quando per esempio cambiate il cost dell'hashing. La verifica avviene secondo le impostazioni salvate e, se needsRehash() restituisce true, bisogna creare di nuovo l'hash, questa volta con i nuovi parametri, e salvarlo di nuovo nel database. Così gli hash salvati si “aggiornano” automaticamente quando gli utenti accedono.

if ($passwords->needsRehash($hash)) {
	$hash = $passwords->hash($password);
	// salviamo $hash nel database
}
versione: 4.x