web-dev-qa-db-fra.com

Utilisation de PHP 5.5's fonction password_hash et password_verify

Supposons que je veuille stocker un mot de passe pour un utilisateur, serait-ce la bonne façon de le faire avec la fonction PHP 5.5 password_hash() (ou cette version pour PHP 5.3.7+: https://github.com/ircmaxell/password_compat )?

$options = array("cost" => 10, "salt" => uniqid());
$hash = password_hash($password, PASSWORD_BCRYPT, $options);

Ensuite, je ferais:

mysql_query("INSERT INTO users(username,password, salt) VALUES($username, $hash, " . $options['salt']);

Pour insérer dans la base de données.

Ensuite pour vérifier:

$row = mysql_fetch_assoc(mysql_query("SELECT salt FROM users WHERE id=$userid"));
$salt = $row["salt"];
$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 10, "salt" => $salt));

if (password_verify($password, $hash) {
    // Verified
}
32
Doug Smith

Ignorant les problèmes avec vos relevés de base de données pour l'instant, je répondrai à la question concernant password_hash.

Bref, non, ce n'est pas comme ça qu'on fait. Vous ne voulez pas stocker le sel seul, vous devez stocker à la fois le hachage et le sel, puis utiliser les deux pour vérifier le mot de passe. password_hash Renvoie une chaîne contenant les deux.

La fonction password_hash Renvoie une chaîne qui contient à la fois le hachage et le sel. Alors:

$hashAndSalt = password_hash($password, PASSWORD_BCRYPT);
// Insert $hashAndSalt into database against user

Ensuite pour vérifier:

// Fetch hash+salt from database, place in $hashAndSalt variable
// and then to verify $password:
if (password_verify($password, $hashAndSalt)) {
   // Verified
}

En outre, comme le suggèrent les commentaires, si vous êtes intéressé par la sécurité, vous pouvez consulter mysqli (ext/mysql Est déconseillé en PHP5.5), ainsi que cet article sur l'injection SQL: - http://php.net/manual/en/security.database.sql-injection.php

59
Pete

L'utilisation de votre propre sel n'est pas recommandée et, à partir de PHP 7, son utilisation est déconseillée . Pour comprendre pourquoi, l'auteur de password_hash a partagé ces réflexions (lien disparu)

Une chose est devenue très claire pour moi: l'option sel est dangereuse. Je n'ai pas encore vu une seule utilisation de l'option sel qui a été encore décente. Chaque utilisation va de mauvaise (en passant la sortie de mt_Rand ()) à dangereuse (chaînes statiques) à folle (en passant le mot de passe comme son propre sel).

Je suis arrivé à la conclusion que je ne pense pas que nous devrions permettre aux utilisateurs de spécifier le sel.

Il a même fait ce commentaire dans SO chat notant à quel point le passage de votre propre sel peut être mauvais

11
Machavity

Notez cela sur php.net

Avertissement

L'option salt est déconseillée depuis PHP 7.0.0. Il est désormais préférable d'utiliser simplement le sel généré par défaut.

Conclusion? Oubliez l'option sel.

Ce serait tout à fait suffisant password_hash('password', PASSWORD_DEFAULT) * (ou _BCRYPT)

7
Spooky

Vous ne devez pas entrer votre propre sel, laisser le sel vide, la fonction générera un bon sel aléatoire.

Insérez dans la base de données (ou fichier ou tout ce que vous utilisez) toute la chaîne retournée par la fonction. il contient: id d'algorithme, coût, sel (22 caractères) et mot de passe de hachage.

La chaîne entière est requise pour utiliser password_verify (). Le sel est aléatoire et ne nuit pas à tomber entre de mauvaises mains (avec un mot de passe haché). Cela empêche (ou très difficile) d'utiliser des ensembles prêts générés des listes de mots de passe et des hachages - les tables Rainbow.

Vous devriez envisager d'ajouter un paramètre de coût. Par défaut (si omis) est 1 - si supérieur alors la fonction calcule le hachage plus longtemps. Augmentation du coût de 1, double le temps nécessaire pour générer un hachage (et donc allonger le temps nécessaire pour briser le mot de passe)

$hash = password_hash($password, PASSWORD_BCRYPT, array("cost" => 10));

vous devez définir ce paramètre en fonction de la vérification de la vitesse sur votre serveur. Il est recommandé que la fonction effectue 100 ms + (certains préfèrent la faire 250 ms). Habituellement, le coût = 10 ou 11 est un bon choix (en 2015).

Pour augmenter la sécurité, vous souhaiterez peut-être ajouter aux mots de passe une longue chaîne secrète (50-60 caractères est un bon choix). avant d'utiliser password_hash () ou password_verify ().

$secret_string = 'asCaahC72D2bywdu@#$@#$234';
$password  = trim($_POST['user_password']) . $secret_string;
// here use password_* function

Attention L'utilisation du PASSWORD_BCRYPT pour le paramètre algo entraînera la raccourcissement du paramètre de mot de passe à une longueur maximale de 72 caractères.

Si $ password est plus long que 72 caractères et que vous modifiez ou ajoutez 73 ou 90 caractères, le hachage ne changera pas. Facultatif, coller $ secret_string devrait être à la fin (après le mot de passe de l'utilisateur et pas avant).

5
Adam