Nettoyage des mots de passe utilisateur

98

Comment dois-je é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 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 les questions PHP liées au stockage des mots de passe; le développeur souhaite souvent nettoyer le mot de passe à l'aide de fonctions telles que escape_string()(dans diverses itérations) htmlspecialchars(), addslashes()et d'autres avant de le hacher et de le stocker dans la base de données.

Jay Blanchard
la source
1
Vous pouvez encoder en base64 par l'utilisateur
MSS
Non @MSS, vous ne devriez pas parce que base64 est un encodage , pas un cryptage ou un hachage . Les mots de passe doivent toujours être hachés .
Jay Blanchard
1
Je veux dire avant le hachage;)
MSS
Vous ne devriez pas et n'avez pas besoin de le faire avant le hachage. Cela vous obligera à écrire du code supplémentaire inutile @MSS
Jay Blanchard

Réponses:

99

Vous ne devriez jamais échapper, couper ou utiliser tout autre mécanisme de nettoyage sur les mots de passe que vous hacherez avec PHP password_hash()pour un certain nombre de raisons, dont la plus importante est que le nettoyage supplémentaire du mot de passe nécessite du code supplémentaire inutile.

Vous argumenterez (et vous le verrez dans chaque article où les données utilisateur sont acceptées pour une utilisation dans vos systèmes) que nous devrions nettoyer toutes les entrées utilisateur et que vous auriez raison pour toutes les autres informations que nous acceptons de nos utilisateurs. Les mots de passe sont différents. Les mots de passe hachés ne peuvent pas offrir de 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 hachage d'un mot de passe consiste à rendre le mot de passe sûr 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 nécessaire pour des raisons de sécurité

Si vous suivez les mantras permettant aux utilisateurs d'utiliser les mots de passe / phrases qu'ils souhaitent et que vous ne limitez pas les mots de passe , autoriser n'importe quelle longueur, n'importe quel nombre d'espaces et tout hachage de caractères spéciaux rendra le mot de passe / phrase de passe sûr, peu importe ce qu'il contient le mot de passe. À l'heure actuelle, le hachage le plus courant (par défaut), PASSWORD_BCRYPTtransforme le mot de passe en une chaîne de 60 caractères de large contenant un sel aléatoire avec les informations de mot de passe hachées 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. Il en résultera toujours un hachage utilisant le format de cryptage «$ 2y $», qui est toujours large de 60 caractères.

L'espace requis pour stocker le hachage est sujet à changement à 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 serait hachée, ce qui la rendrait non exécutable par le moteur SQL, par exemple,

SELECT * FROM `users`;

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

Voyons comment différentes méthodes de désinfection 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 découpage 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éutiliser avant de les comparer password_verify(). Ce qui suit échouerait:

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

Vous devrez 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 et n'améliorera pas le hachage.


Vous utilisez une version PHP inférieure à 5.5? Vous pouvez utiliser le password_hash() pack de compatibilité .

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

Jay Blanchard
la source
13
Non. S'il a créé son mot de passe avec des espaces de fin, ce qui est autorisé, il doit les utiliser lors de la connexion @DanBracuk
Jay Blanchard
12
Comment ça @DanBracuk? Si nous permettons à l'utilisateur de configurer le mot de passe qu'il souhaite, y compris les espaces de début / de fin?
Jay Blanchard
16
C'est pourquoi la plupart des choses vous obligent à saisir deux fois le mot de passe choisi. Si l'utilisateur a ajouté les espaces par accident, il le comprendra avant d'aller plus loin. Si l'utilisateur l'a fait exprès, ce n'est pas un problème.
J'ai combattu un ours une fois.
4
@MargaretBloom, une règle de base n'est qu'une heuristique. Nous avons parfois encore besoin de réfléchir, comme pour les mots de passe. Vous dites "personne ne sait comment les choses vont changer à l'avenir", mais il semble que si quelque chose va changer, c'est la façon dont nous échappons aux données avant de les mettre dans la base de données, auquel cas les utilisateurs se retrouveraient verrouillés lorsque leurs mots de passe non correspondent plus à ce que nous avons stocké. Quel est le danger de ne pas échapper aux hachages de mots de passe par rapport au danger de leur échapper?
DavidS
3
Exactement: vous allez bien sûr "échapper au hachage" dans le sens limité de le passer correctement à une requête SQL paramétrée, où du code dans votre connecteur SQL peut ou ne peut pas faire quoi que ce soit qui corresponde à "échapper", vous ne Je sais et je m'en fiche. Vous n'aurez tout simplement pas besoin d'écrire de code spécifique pour y parvenir, car c'est une routine pour toutes vos requêtes SQL, sauf si vous avez déjà pris de mauvaises décisions dans la vie.
Steve Jessop
36

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

  1. Règle de mappage supplémentaire: toutes les instances d'espace non ASCII DOIVENT être mappées vers l'espace ASCII (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: la forme de normalisation Unicode C (NFC) DOIT être appliquée à 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é.

legoscia
la source
3
@DavidS, un Mac Book nord-américain super brillant (que Joe a utilisé juste avant de partir) et un ordinateur de café Internet taïwanais mal internationalisé (que Joe essaie d'utiliser pour télécharger est une carte d'embarquement de retour).
Margaret Bloom
2
Cela semble jingo. :-) Merci quand même.
DavidS
3
Hmm. Si vous faites cela, vous devez également valider les mots de passe pour rejeter ceux qui contiennent des caractères non encore attribués. Ce serait terrible si un utilisateur utilise NEWFANGLED SPACE, que votre application ne reconnaît pas et donc hache tel quel, puis vous mettez à niveau votre base de données de caractères Unicode et soudain NEWFANGLED SPACE est mappé à SPACE avant le hachage, de sorte qu'il ne peut plus entrer un mot de passe que votre application hachera avec l'ancien hachage.
ruakh
4
@JayBlanchard Parce que lorsque vous appuyez sur une barre d'espace sur une machine et lorsque vous appuyez dessus sur une autre machine, vous pouvez obtenir deux points de code Unicode différents, et ils auront deux encodages UTF-8 différents, sans que l'utilisateur ne soit au courant de quoi que ce soit. On pourrait soutenir que c'est un problème que vous souhaitez ignorer, mais la RFC 7613 a été corroborée par de tels problèmes de la vie réelle, ce n'est pas une recommandation de travail.
Réintégrer Monica le
1
@ruakh Une fois que vous avez décidé de gérer les mots de passe d'une certaine manière, ils doivent rester traités de cette façon, sinon les choses vont casser pour les cas d'utilisation existants. Si vous envisagez de modifier la méthode de prétraitement à l'avenir, vous devez la stocker avec la représentation prétraitée et hachée du mot de passe. De cette façon, une fois que vous recevez l'entrée, vous sélectionnez la méthode de prétraitement / hachage en fonction de ce à quoi vous comparez.
Réintégrer Monica le