En utilisant Argon2 pour hacher des mots de passe dans mon application, j'ai remarqué qu'il génère une chaîne comme celle-ci (par exemple pour le mot de passe "lapin"):
$argon2i$v=19$m=65536,t=3,p=1$YOtX2//7NoD/owm8RZ8llw==$fPn4sPgkFAuBJo3M3UzcGss3dJysxLJdPdvojRF20ZE=
Ma compréhension est que tout ce qui précède p=
Est un paramètre, le corps du p=
Est le sel et la dernière partie est le mot de passe haché.
Est-il acceptable de stocker cela dans un champ dans une base de données SQL (varchar(99)
dans ce cas), ou la chaîne doit-elle être séparée en ses parties constituantes? Dois-je stocker le sel séparément du mot de passe haché et conserver les paramètres dans le code?
Vous devez le stocker dans un seul champ. N'essayez pas de le diviser en parties.
Je sais que cela peut sembler un peu peu intuitif pour les personnes issues d'une base de données, où le mode de fonctionnement consiste à normaliser les données et à utiliser des chaînes sérialisées est considéré comme un vilain piratage. Mais à partir d'une pratique de sécurité, cela est parfaitement logique.
Pourquoi? Parce que la plus petite unité sur laquelle le développeur individuel doit opérer est cette chaîne complète. C'est ce que l'application doit passer à la bibliothèque de hachage pour vérifier si un mot de passe fourni est correct ou non. Du point de vue des développeurs, la bibliothèque de hachage peut être une boîte noire, et elle n'a pas besoin de se soucier de ce que ces parties embêtantes signifient réellement.
C'est une bonne chose, car la plupart des développeurs sont des humains imparfaits (je sais, parce que j'en suis un moi-même). Si vous leur permettez de séparer cette chaîne puis d'essayer de la réassembler, ils gâcheront probablement les choses, comme donner à tous les utilisateurs le même sel ou pas de sel du tout.
Seul le stockage des paramètres dans le code est également une mauvaise idée. À mesure que les processeurs s'accélèrent, vous souhaiterez peut-être augmenter le facteur de coût à l'avenir. Pendant la phase de migration, différents mots de passe auront différents facteurs de coût. Vous aurez donc besoin d'informations sur le niveau de mot de passe pour savoir quel facteur de coût a été utilisé pour le hacher.
Ce qui vous manque, c'est que les hachages fonctionnent sur les données d'origine, moins la chaîne d'origine. Lorsque vous souhaitez valider une chaîne par rapport à un hachage, vous prenez la chaîne fournie, plus les données de hachage d'origine (coût, sel, etc.) et vous générez un nouveau hachage. Si le nouveau hachage correspond à l'ancien, la chaîne est alors validée (en d'autres termes, la chaîne n'est jamais déchiffrée, elle est re-hachée).
Avoir du sel ne vous aide pas à la force brute. Le sel est une partie essentielle d'un hachage de la même manière que les gobelets font partie d'une serrure. Si vous retirez l'un ou l'autre, personne ne peut l'utiliser.
Séparer le stockage est inutile. Vous devrez réassembler le hachage terminé pour le valider dans la plupart des cas. C'est pourquoi tous les composants sont stockés dans une seule chaîne pratique par défaut.
Oui, vous pouvez le stocker dans un seul champ, et de nombreuses bases de données/applications stockent le sel + hachage dans un seul champ/fichier, etc.
Le plus célèbre est Linux (qui n'est pas une base de données), qui stocke le hachage dans le fichier/etc/shadow en utilisant le format:
"$ id $ salt $ hashed", la forme imprimable d'un hachage de mot de passe tel que produit par crypt (C), où "$ id" est l'algorithme utilisé. (Sur GNU/Linux, "$ 1 $" signifie MD5, "$ 2a $" est Blowfish, "$ 2y $" est Blowfish (gestion correcte des caractères 8 bits), "$ 5 $" est SHA-256 et "$ 6 $ "est SHA-512, [4] d'autres Unix peuvent avoir des valeurs différentes, comme NetBSD.
(source: https://en.wikipedia.org/wiki/Passwd )
Le sel n'est pas censé être secret (ou du moins pas plus secret que le hasch). Son objectif principal est de rendre les attaques par forçage brut beaucoup plus difficiles, car l'attaquant doit utiliser un sel différent pour chaque utilisateur individuel.
Mais votre question est plus nuancée - parce que vous ne vous interrogez pas seulement sur les sels mais aussi sur les paramètres. Des choses comme l'algorithme de hachage, le nombre d'itérations et le sel. Dans tous les cas, ne stockez pas cela dans le code, ils appartiennent toujours à la base de données.
Imaginez que vous avez un groupe d'utilisateurs et que vous avez utilisé SHA1 comme algorithme de hachage. Ainsi, votre champ de base de données serait quelque chose comme SHA1: SALT: HASH .
Si vous vouliez mettre à niveau votre base de données vers BCRYPT, comment feriez-vous cela?
En règle générale, vous déployez du code de sorte que lorsqu'un utilisateur ouvre une session, vous vérifiez le mot de passe et, s'il est valide, vous ré-hachez le mot de passe avec un algorithme plus récent. Maintenant, le champ de l'utilisateur ressemble à ceci: BCRYPT: SALT: HASH .
Mais alors certains utilisateurs seraient sur SHA1, et d'autres sur BCRYPT, et puisque c'est au niveau de l'utilisateur, vous avez besoin des paramètres qui indiquent à votre code quels utilisateurs doivent être dans la base de données.
En bref, le stockage des paramètres et du hachage dans un seul champ est OK, mais les diviser pour une raison quelconque (efficacité, code plus facile, etc.) est également OK. Ce qui ne va pas, c'est de le stocker dans votre code :)
TL: DR
Troy Hunt a récemment publié un podcast suggérant qu'au lieu de migrer vers BCRYPT de la manière ci-dessus, il est plus efficace de simplement prendre tous les hachages SHA1 actuellement dans la base de données et de les hacher en utilisant BCRYPT.
Effectivement BCRYPT(SHA1(clear_password))
Lorsqu'un utilisateur se connecte, vous
BCRYPT(SHA1(clear_password)) == <db_field>
De cette façon, tout le monde sur la plate-forme est mis à niveau en même temps et vous n'avez pas de base de données avec plusieurs formats de hachage pour les mots de passe. Très propre et très agréable.
Je pense que cette idée est parfaitement logique, mais même si tout le monde migre en même temps, ce n'est pas instantané. À moins que vous ne vouliez accepter un certain temps d'arrêt sur l'application (pendant que vous hachez de nouveau tous les mots de passe), il y aura toujours un petit intervalle de temps où certains utilisateurs sont sur BCRYPT et d'autres sur SHA1, donc votre base de données devrait toujours stocker le paramètres de l'algorithme de hachage, et votre code s'exécuterait en fonction de celui-ci.
Du point de vue de la sécurité, peu importe si le sel et le mot de passe haché sont stockés dans un seul champ ou des champs séparés, bien que je penche vers un seul champ pour plus de simplicité. La seule raison de les séparer est si votre code d'application doit passer le sel et le mot de passe séparément à la fonction de validation. Si votre code d'application ne nécessite qu'une seule chaîne combinée, vous pouvez aussi bien le stocker de cette façon.
Par exemple, l'ancienne appartenance ASP.NET divise le hachage et le sel de mot de passe en deux champs de base de données, et la nouvelle identité ASP.NET a le hachage et le sel dans un seul champ de base de données, et à son tour, les nouvelles fonctions ont été modifiées pour gérer la chaîne unique comme entrées et sorties.
Est-il acceptable de stocker cela dans un champ dans une base de données SQL (varchar (99) dans ce cas)
Non. La taille des données peut changer à un moment donné. Un champ varchar (MAX) doit être utilisé à moins que les spécifications n'indiquent que la taille sera toujours exactement 99 et qu'il n'y aura aucune variation par rapport à cela jamais. Laissez la base de données prendre en charge les exigences de stockage.
Pour savoir si son plus ou moins sûr, nous devons comprendre le but d'un sel.
Un sel sert à quelques fins (auxquelles je peux penser)
Une attaque par dictionnaire est l'endroit où un mot logique est utilisé dans le cadre d'un mot de passe. L'archétype étant le mot password
ou même P@ssW0rd
. Les gens sont imparfaits et il leur est plus facile de se souvenir des mots puis des chaînes aléatoires de lettres et de chiffres. Une attaque par dictionnaire s'appuie sur cela pour raccourcir le chemin emprunté par une attaque par force brute. Évidemment, si nous y ajoutons un morceau aléatoire, cela rend ce type d'attaque impossible, ou inutile, et les remet à la force brute forçant le tout.
Si un attaquant connaît le sel utilisé, il devra modifier tous ses fichiers de dictionnaire pour chaque mot de passe, et cela suppose qu'il sait comment le sel est ajouté au mot de passe d'origine. Un grand avantage d'une liste de dictionnaires est que vous prenez 1 000 mots de passe et 1 million de mots de dictionnaire. Ensuite, vous les parcourez en essayant d'obtenir quelques correspondances sur des mots de passe plus faibles. Donc, devoir éditer 1 million de mots 1000 fois n'est tout simplement pas vraiment pratique.
Une table Rainbow est l'endroit où les hachages sont pré-calculés et stockés dans une sorte de base de données. Par exemple, vous pouvez prendre MD5 et commencer à hacher des éléments aléatoires et à les enregistrer. Ensuite, lorsque vous souhaitez déchiffrer un mot de passe, il vous suffit de rechercher dans le tableau Rainbow.
Si un attaquant a le sel, il doit recompiler la table Rainbow pour chaque sel utilisé. L'avantage de cette attaque est d'avoir ces données compilées à l'avance et de les réutiliser encore et encore. Cela les ramène au forçage brutal du mot de passe. En salant et en salant tous les mots de passe différemment, cela signifie essentiellement que vous devez recalculer la table Rainbow pour chaque sel. C'est pourquoi il est important d'utiliser des sels différents pour chaque mot de passe.
Estival
Aucune de ces raisons ne repose vraiment sur le secret du sel. Évidemment, ils sont tous moins forts si un attaquant connaît le sel. Mais les informations supplémentaires qu'ils obtiendront les aideront toujours. Je ne dirais donc pas de faire de la publicité, mais il y a un dicton sur la sécurité basée sur l'obscurité ...
Avis de non-responsabilité Je ne suis en aucun cas un expert en cryptologie, mais ce sont quelques-unes des principales raisons qui me viennent à l'esprit lorsque je pense aux sels.
J'espère que cela pourra aider.
Le sel est juste utilisé pour bloquer les attaques des tables Rainbow. Par conséquent, votre sel peut être stocké avec le mot de passe haché comme cela se fait sur le système GNU/Linux le plus récent où le sel est stocké dans/etc/shadow.