web-dev-qa-db-fra.com

Nettoyage des mots de passe utilisateur

Comment échapper ou nettoyer les mots de passe fournis par l'utilisateur avant de les hacher et de les stocker dans ma base de données?

Lorsque les développeurs de PHP envisagent de hacher les mots de passe des utilisateurs à des fins de sécurité, ils ont souvent tendance à penser à ces mots de passe comme ils le feraient pour toute autre donnée fournie par l'utilisateur. Ce sujet revient souvent dans PHP questions liées au stockage des mots de passe; le développeur souhaite souvent nettoyer le mot de passe en utilisant des fonctions telles que escape_string() (dans diverses itérations), htmlspecialchars(), addslashes() et autres avant de le hacher et de le stocker dans la base de données.

93
Jay Blanchard

Vous ne devez jamais échapper, rogner ou utiliser un autre mécanisme de nettoyage sur les mots de passe que vous allez hacher avec PHP password_hash() pour un certain nombre de raisons, la plus importante étant parce que le nettoyage du mot de passe nécessite un code supplémentaire inutile.

Vous soutiendrez (et vous le voyez dans chaque publication où les données utilisateur sont acceptées pour une utilisation dans vos systèmes) que nous devons nettoyer toutes les entrées utilisateur et vous auriez raison pour chaque autre élément d'information que nous acceptons de nos utilisateurs. Les mots de passe sont différents. Les mots de passe hachés ne peuvent offrir aucune menace d'injection SQL car la chaîne est transformée en hachage avant d'être stockée dans la base de données.

Le fait de hacher un mot de passe est le fait de sécuriser le mot de passe pour le stocker dans votre base de données. La fonction de hachage ne donne aucune signification particulière à aucun octet, donc aucun nettoyage de son entrée n'est requis pour des raisons de sécurité

Si vous suivez les mantras permettant aux utilisateurs d'utiliser les mots de passe/phrases qu'ils désirent et vous ne limitez pas les mots de passe , autorisant toute longueur, tout nombre d'espaces et tous les caractères spéciaux le hachage sécurisera le mot de passe/phrase de passe, quel que soit le contenu du mot de passe. À l'heure actuelle, le hachage le plus courant (par défaut), PASSWORD_BCRYPT , transforme le mot de passe en une chaîne de 60 caractères contenant un sel aléatoire avec les informations du mot de passe haché et un coût ( le coût algorithmique de la création du hachage):

PASSWORD_BCRYPT est utilisé pour créer de nouveaux hachages de mot de passe à l'aide de l'algorithme CRYPT_BLOWFISH. Cela se traduira toujours par un hachage en utilisant le format de cryptage "$ 2y $", qui fait toujours 60 caractères de large.

L'espace requis pour stocker le hachage est susceptible de changer à mesure que différentes méthodes de hachage sont ajoutées à la fonction, il est donc toujours préférable d'augmenter le type de colonne pour le hachage stocké, tel que VARCHAR(255) ou TEXT.

Vous pouvez utiliser une requête SQL complète comme mot de passe et elle sera hachée, ce qui la rendra non exécutable par le moteur SQL, par exemple,

SELECT * FROM `users`;

Peut être haché en $2y$10$1tOKcWUWBW5gBka04tGMO.BH7gs/qjAHZsC5wyG0zmI2C.KgaqU5G

Voyons comment les différentes méthodes de nettoyage affectent le mot de passe -

Le mot de passe est I'm a "dessert topping" & a <floor wax>! (Il y a 5 espaces à la fin du mot de passe qui ne sont pas affichés ici.)

Lorsque nous appliquons les méthodes de rognage suivantes, nous obtenons des résultats très différents:

var_dump(trim($_POST['upassword']));
var_dump(htmlentities($_POST['upassword']));
var_dump(htmlspecialchars($_POST['upassword']));
var_dump(addslashes($_POST['upassword']));
var_dump(strip_tags($_POST['upassword']));

Résultats:

string(40) "I'm a "dessert topping" & a <floor wax>!" // spaces at the end are missing
string(65) "I'm a &quot;dessert topping&quot; &amp; a &lt;floor wax&gt;!     " // double quotes, ampersand and braces have been changed
string(65) "I'm a &quot;dessert topping&quot; &amp; a &lt;floor wax&gt;!     " // same here
string(48) "I\'m a \"dessert topping\" & a <floor wax>!     " // escape characters have been added
string(34) "I'm a "dessert topping" & a !     " // looks like we have something missing

Que se passe-t-il lorsque nous les envoyons à password_hash()? Ils sont tous hachés, tout comme la requête ci-dessus. Le problème survient lorsque vous essayez de vérifier le mot de passe. Si nous employons une ou plusieurs de ces méthodes, nous devons les réemployer avant de les comparer avec password_verify() . Les éléments suivants échoueraient:

password_verify($_POST['upassword'], $hashed_password); // where $hashed_password comes from a database query

Vous devez exécuter le mot de passe publié via la méthode de nettoyage que vous avez choisie avant d'utiliser le résultat de cela dans la vérification du mot de passe. Il s'agit d'un ensemble d'étapes inutiles qui n'amélioreront pas le hachage.


En utilisant une PHP version inférieure à 5.5? Vous pouvez utiliser la password_hash()pack de compatibilité .

Vous ne devriez vraiment pas utiliser hachages de mot de passe MD5 .

95
Jay Blanchard

Avant de hacher le mot de passe, vous devez le normaliser comme décrit dans section 4 de la RFC 761 . En particulier:

  1. Règle de mappage supplémentaire: toute instance d'espace non ASCII DOIT être mappée à ASCII espace (U + 0020); un espace non ASCII est tout point de code Unicode ayant une catégorie générale Unicode de "Zs") "(à l'exception de U + 0020).

et:

  1. Règle de normalisation: le formulaire de normalisation Unicode C (NFC) DOIT être appliqué à tous les caractères.

Cela tente de garantir que si l'utilisateur tape le même mot de passe mais en utilisant une méthode d'entrée différente, le mot de passe doit toujours être accepté.

35
legoscia