PHP
Fonctions de hachage du mot de passe
Recherche…
Introduction
Comme de plus en plus de services Web sécurisés évitent de stocker les mots de passe au format texte brut, des langages tels que PHP fournissent diverses fonctions de hachage (non décryptables) pour prendre en charge la norme industrielle la plus sécurisée. Cette rubrique fournit une documentation pour un hachage correct avec PHP.
Syntaxe
-
string password_hash ( string $password , integer $algo [, array $options ] )
-
boolean password_verify ( string $password , string $hash )
-
boolean password_needs_rehash ( string $hash , integer $algo [, array $options ] )
-
array password_get_info ( string $hash )
Remarques
Avant PHP 5.5, vous pouvez utiliser le pack de compatibilité pour fournir les fonctions password_*
. Il est fortement recommandé d'utiliser le pack de compatibilité si vous pouvez le faire.
Avec ou sans le pack de compatibilité, la fonctionnalité Bcrypt correcte via crypt()
repose sur PHP 5.3.7+, sinon vous devez limiter les mots de passe aux jeux de caractères ASCII uniquement.
Note: Si vous utilisez PHP 5.5 ou moins, vous utilisez une version non prise en charge de PHP qui ne reçoit plus de mises à jour de sécurité. Mettez à jour dès que possible, vous pouvez mettre à jour vos mots de passe après.
Sélection d'algorithme
Algorithmes sécurisés
- bcrypt est votre meilleure option tant que vous utilisez l'étirement des touches pour augmenter le temps de calcul du hachage, car cela rend les attaques par force brute extrêmement lentes .
- argon2 est une autre option qui sera disponible en PHP 7.2 .
Algorithmes non sécurisés
Les algorithmes de hachage suivants sont peu sûrs ou impropres à l'usage et ne doivent donc pas être utilisés . Ils ne sont jamais adaptés au hachage de mot de passe, car ils sont conçus pour une digestion rapide au lieu d'un hachage de mot de passe de force lent et difficile.
Si vous en utilisez , même avec des sels, vous devez passer à l'un des algorithmes sécurisés recommandés dès que possible .
Algorithmes considérés peu sûrs:
- MD4 - attaque de collision trouvée en 1995
- MD5 - attaque de collision trouvée en 2005
- SHA-1 - attaque de collision démontrée en 2015
Certains algorithmes peuvent être utilisés en toute sécurité comme algorithme de résumé de message pour prouver l'authenticité, mais jamais comme algorithme de hachage de mot de passe :
- SHA-2
- SHA-3
Remarque: les hachages forts tels que SHA256 et SHA512 ne sont ni interrompus ni robustes, mais il est généralement plus sûr d'utiliser les fonctions de hachage bcrypt ou argon2 car les attaques par force brute contre ces algorithmes sont beaucoup plus difficiles pour les ordinateurs classiques.
Déterminer si un hachage de mot de passe existant peut être mis à niveau vers un algorithme plus puissant
Si vous utilisez la méthode PASSWORD_DEFAULT
pour permettre au système de choisir le meilleur algorithme pour hacher vos mots de passe, à mesure que la valeur par défaut augmente, vous pouvez souhaiter ressasser les anciens mots de passe lorsque les utilisateurs se connectent.
<?php
// first determine if a supplied password is valid
if (password_verify($plaintextPassword, $hashedPassword)) {
// now determine if the existing hash was created with an algorithm that is
// no longer the default
if (password_needs_rehash($hashedPassword, PASSWORD_DEFAULT)) {
// create a new hash with the new default
$newHashedPassword = password_hash($plaintextPassword, PASSWORD_DEFAULT);
// and then save it to your data store
//$db->update(...);
}
}
?>
Si les fonctions password_ * ne sont pas disponibles sur votre système (et que vous ne pouvez pas utiliser le pack de compatibilité lié dans les remarques ci-dessous), vous pouvez déterminer l'algorithme et créer le hachage d'origine selon une méthode similaire à celle-ci:
<?php
if (substr($hashedPassword, 0, 4) == '$2y$' && strlen($hashedPassword) == 60) {
echo 'Algorithm is Bcrypt';
// the "cost" determines how strong this version of Bcrypt is
preg_match('/\$2y\$(\d+)\$/', $hashedPassword, $matches);
$cost = $matches[1];
echo 'Bcrypt cost is '.$cost;
}
?>
Créer un hachage de mot de passe
Créez des hachages de mots de passe en utilisant password_hash()
pour utiliser le hachage standard ou la dérivation de clés des meilleures pratiques du secteur. Au moment de l'écriture, la norme est bcrypt , ce qui signifie que PASSWORD_DEFAULT
contient la même valeur que PASSWORD_BCRYPT
.
$options = [
'cost' => 12,
];
$hashedPassword = password_hash($plaintextPassword, PASSWORD_DEFAULT, $options);
Le troisième paramètre n'est pas obligatoire .
La valeur 'cost'
doit être choisie en fonction du matériel de votre serveur de production. L'augmenter rendra le mot de passe plus coûteux à générer. Plus il est coûteux de générer plus il faudra de temps pour que quelqu'un essaie de le générer pour le générer. Le coût devrait idéalement être aussi élevé que possible, mais en pratique, il devrait être réglé de manière à ne pas trop ralentir le processus. Quelque part entre 0,1 et 0,4 seconde serait bien. Utilisez la valeur par défaut si vous avez un doute.
Sur PHP inférieur à 5.5.0, les fonctions password_*
ne sont pas disponibles. Vous devez utiliser le pack de compatibilité pour remplacer ces fonctions. Notez que le pack de compatibilité requiert PHP 5.3.7 ou supérieur ou une version $2y
correctif $2y
(comme RedHat le fournit).
Si vous ne pouvez pas les utiliser, vous pouvez implémenter un hachage de mot de passe avec crypt()
Comme password_hash()
est implémenté comme un wrapper autour de la fonction crypt()
, vous n'avez besoin de perdre aucune fonctionnalité.
// this is a simple implementation of a bcrypt hash otherwise compatible
// with `password_hash()`
// not guaranteed to maintain the same cryptographic strength of the full `password_hash()`
// implementation
// if `CRYPT_BLOWFISH` is 1, that means bcrypt (which uses blowfish) is available
// on your system
if (CRYPT_BLOWFISH == 1) {
$salt = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
$salt = base64_encode($salt);
// crypt uses a modified base64 variant
$source = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
$dest = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$salt = strtr(rtrim($salt, '='), $source, $dest);
$salt = substr($salt, 0, 22);
// `crypt()` determines which hashing algorithm to use by the form of the salt string
// that is passed in
$hashedPassword = crypt($plaintextPassword, '$2y$10$'.$salt.'$');
}
Salt pour mot de passe hash
Malgré la fiabilité de l'algorithme de cryptage, il existe toujours une vulnérabilité contre les tables arc-en-ciel . C'est la raison pour laquelle il est recommandé d'utiliser du sel .
Un sel est quelque chose qui est ajouté au mot de passe avant le hachage pour rendre la chaîne source unique. Compte tenu de deux mots de passe identiques, les hachages résultants seront également uniques, car leurs sels sont uniques.
Un sel aléatoire est l'un des éléments les plus importants de la sécurité de votre mot de passe. Cela signifie que même avec une table de recherche de hachages de mots de passe connus, un attaquant ne peut pas faire correspondre le hachage du mot de passe de votre utilisateur avec le hachage du mot de passe de la base de données. Vous devez toujours utiliser des sels aléatoires et cryptographiquement sécurisés. Lire la suite
Avec l'algorithme bcrypt
password_hash()
, le sel en texte brut est stocké avec le hachage résultant, ce qui signifie que le hachage peut être transféré sur différents systèmes et plates-formes et être toujours comparé au mot de passe d'origine.
Même si cela est déconseillé, vous pouvez utiliser l'option salt
pour définir votre propre sel aléatoire.
$options = [
'salt' => $salt, //see example below
];
Important Si vous omettez cette option, un sel aléatoire sera généré par password_hash () pour chaque mot de passe haché. C'est le mode de fonctionnement prévu.
L'option salt a été déconseillée à partir de PHP 7.0.0. Il est maintenant préférable d'utiliser simplement le sel généré par défaut.
Vérification d'un mot de passe contre un hachage
password_verify()
est la fonction intégrée fournie (depuis PHP 5.5) pour vérifier la validité d'un mot de passe par rapport à un hachage connu.
<?php
if (password_verify($plaintextPassword, $hashedPassword)) {
echo 'Valid Password';
}
else {
echo 'Invalid Password.';
}
?>
Tous les algorithmes de hachage pris en charge stockent des informations identifiant le hachage utilisé dans le hachage lui-même, il n'est donc pas nécessaire d'indiquer l'algorithme que vous utilisez pour encoder le mot de passe en texte brut.
Si les fonctions password_ * ne sont pas disponibles sur votre système (et que vous ne pouvez pas utiliser le pack de compatibilité lié dans les remarques ci-dessous), vous pouvez implémenter la vérification du mot de passe avec la fonction crypt()
. Veuillez noter que des précautions spécifiques doivent être prises pour éviter les attaques par synchronisation .
<?php
// not guaranteed to maintain the same cryptographic strength of the full `password_hash()`
// implementation
if (CRYPT_BLOWFISH == 1) {
// `crypt()` discards all characters beyond the salt length, so we can pass in
// the full hashed password
$hashedCheck = crypt($plaintextPassword, $hashedPassword);
// this a basic constant-time comparison based on the full implementation used
// in `password_hash()`
$status = 0;
for ($i=0; $i<strlen($hashedCheck); $i++) {
$status |= (ord($hashedCheck[$i]) ^ ord($hashedPassword[$i]));
}
if ($status === 0) {
echo 'Valid Password';
}
else {
echo 'Invalid Password';
}
}
?>