Hachage des mots de passe

Pour garantir la sécurité de nos utilisateurs, nous ne stockons jamais leurs mots de passe sous forme lisible, mais seulement leur empreinte (appelée hachage). Le hachage ne peut pas être inversé pour retrouver le mot de passe d'origine. Il est important d'utiliser un algorithme sûr pour créer le hachage. La classe Nette\Security\Passwords nous y aide.

Installation et prérequis

Le framework ajoute automatiquement au conteneur DI un service de type Nette\Security\Passwords sous le nom security.passwords. Vous pouvez vous le faire passer par injection de dépendances.

use Nette\Security\Passwords;

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

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

Nous choisissons quel algorithme sûr utiliser pour générer le hachage et nous en configurons les paramètres.

La valeur par défaut est PASSWORD_DEFAULT, ce qui signifie que le choix de l'algorithme est laissé à PHP. L'algorithme peut changer dans des versions plus récentes de PHP si des algorithmes de hachage plus récents et plus robustes apparaissent. Sachez donc que la longueur du hachage obtenu peut changer et stockez-le d'une façon qui puisse accueillir assez de caractères ; 255 est la largeur recommandée.

Exemple de réglage de la vitesse de hachage de l'algorithme bcrypt en modifiant le paramètre cost : (en 2020, la valeur par défaut est 10, hacher un mot de passe prend environ 80 ms ; pour cost 11, environ 160 ms ; pour cost 12, environ 320 ms ; plus c'est lent, meilleure est la protection, une vitesse de 10 à 12 étant déjà considérée comme une protection suffisante)

// nous hacherons les mots de passe avec 2^12 (2^cost) itérations de l'algorithme bcrypt
$passwords = new Passwords(PASSWORD_BCRYPT, ['cost' => 12]);

À l'aide de l'injection de dépendances :

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

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

Crée une instance configurée pour l'algorithme bcrypt. Le paramètre $cost fixe la vitesse de hachage décrite ci-dessus ; si vous l'omettez, la valeur par défaut de PHP est utilisée.

$passwords = Passwords::bcrypt(12);

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

Crée une instance configurée pour l'algorithme Argon2id. Les paramètres omis sont laissés aux valeurs par défaut de PHP. Si PHP a été compilé sans la prise en charge d'Argon2, la méthode lève Nette\NotSupportedException.

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

hash (string $password): string

Génère le hachage du mot de passe.

$res = $passwords->hash($password); // Hache le mot de passe

Le résultat $res est une chaîne qui, outre le hachage lui-même, contient l'identifiant de l'algorithme utilisé, ses réglages et un sel cryptographique (des données aléatoires garantissant qu'un hachage différent est produit pour le même mot de passe). Il est donc rétrocompatible : si vous changez par exemple les paramètres, les hachages stockés avec les réglages précédents restent vérifiables. C'est tout ce résultat qui est stocké en base, il n'est donc pas nécessaire d'y conserver séparément le sel ou les réglages.

verify (string $password, string $hash)bool

Détermine si le mot de passe donné correspond au hachage donné. Obtenez $hash depuis la base d'après le nom d'utilisateur ou l'adresse e-mail saisis.

if ($passwords->verify($password, $hash)) {
	// mot de passe correct
}

needsRehash (string $hash)bool

Détermine si le hachage correspond aux options indiquées dans le constructeur.

Il est utile de s'en servir lorsque vous changez, par exemple, le cost du hachage. La vérification se fait d'après les réglages stockés et, si needsRehash() renvoie true, il faut créer le hachage à nouveau, cette fois avec les nouveaux paramètres, et l'enregistrer de nouveau en base. Cela “met à niveau” automatiquement les hachages stockés lorsque les utilisateurs se connectent.

if ($passwords->needsRehash($hash)) {
	$hash = $passwords->hash($password);
	// enregistrer $hash dans la base
}
version: 4.x