Veuillez noter: Je suis conscient que la méthode appropriée pour le hachage de stockage de mot de passe sécurisé est scrypt ou bcrypt. Cette question n'est pas pour l'implémentation dans un logiciel réel, c'est pour ma propre compréhension.
Connexes
Contexte
Pour autant que je sache, la méthode recommandée/approuvée pour le stockage des vérificateurs de mot de passe consiste à stocker:
$verifier = $salt + hash( $salt + $password )
Où:
hash()
est un algorithme de hachage cryptographique$salt
Est une valeur d'entropie aléatoire aléatoire, uniformément répartie et élevée$password
Est le mot de passe entré par l'utilisateurCertaines personnes conseillent d'ajouter une clé secrète dans le mélange (parfois appelé poivre ). Où le poivre est une constante secrète, à entropie élevée, propre au système.
La justification semble être que même si l'attaquant met la main sur les vérificateurs de mot de passe, il y a de fortes chances qu'il ou elle ne connaisse pas la valeur du poivre. Il est donc plus difficile de monter une attaque réussie.
Donc, ma question est:
L'ajout d'une valeur de poivre en plus d'un sel lors du hachage des mots de passe augmente-t-il la sécurité globale?
Ou la sécurité accrue perçue est-elle basée sur de fausses hypothèses?
Mise à jour rapide
Je connais le but du $salt
(J'ai écrit pas mal réponse longue sur StackOverflow à ce sujet) la clé supplémentaire $pepper
Est pas améliorant ce que fait le sel.
La question est, le $pepper
Ajoute-t-il une sécurité autre à celle du sel?
Dans certaines circonstances, les poivrons peuvent être utiles.
Par exemple, supposons que vous construisez une application Web. Elle se compose de code Webapp (exécuté dans un cadre Webapp, ASP.NET MVC, Pyramide sur Python, peu importe) et une base de données SQL pour le stockage. La webapp et SQL DB s'exécutent sur différents serveurs physiques.
L'attaque la plus courante contre la base de données est une attaque par injection SQL réussie. Ce type d'attaque n'accède pas nécessairement à votre code d'application Web, car l'application Web s'exécute sur un serveur et un ID utilisateur différents.
Vous devez stocker les mots de passe en toute sécurité dans la base de données et trouver quelque chose sous la forme de:
$hashed_password = hash( $salt . $password )
où $salt
est stocké en texte brut dans la base de données, avec la représentation $hashed_password
et choisi au hasard pour chaque mot de passe nouveau ou modifié.
L'aspect le plus important de chaque schéma de hachage de mot de passe est que hash
est un lent fonction de hachage cryptographiquement sécurisée, voir https://security.stackexchange.com/a/31846/10727 pour plus de connaissances de base.
La question est alors, étant donné que l'effort est presque nul pour ajouter une valeur constante au code d'application, et que le code d'application sera généralement pas être compromis lors d'une attaque par injection SQL, est-ce que ce qui suit est nettement meilleur que ce qui précède?
$hashed_password = hash( $pepper . $salt . $password )
où $salt
est stocké en texte brut dans la base de données et $pepper
est une constante stockée en texte brut dans le code d'application (ou la configuration si le code est utilisé sur plusieurs serveurs ou si la source est publique).
L'ajout de $pepper
Est facile - vous créez simplement une constante dans votre code, en entrant une grande valeur aléatoire cryptographiquement sécurisée (par exemple 32 octets à partir de/dev/urandom hex ou base64 encodé) et en l'utilisant constante dans la fonction de hachage de mot de passe. Si vous avez des utilisateurs existants, vous avez besoin d'une stratégie de migration, par exemple ressasser le mot de passe lors de la prochaine connexion et stocker un numéro de version de la stratégie de hachage de mot de passe à côté du hachage.
L'utilisation du $pepper
ajoute à la force du hachage du mot de passe si compromis de la base de données n'implique pas compromis de l'application. Sans connaissance du poivre, les mots de passe restent complètement sécurisés. En raison du sel spécifique au mot de passe, vous ne pouvez même pas savoir si deux mots de passe dans la base de données sont identiques ou non.
La raison en est que hash($pepper . $salt . $password)
construit efficacement une fonction pseudo aléatoire avec $pepper
Comme clé et $salt.$password
Comme entrée (pour des candidats sains hash
comme PBKDF2 avec SHA * , bcrypt ou scrypt). Deux des garanties d'une fonction pseudo-aléatoire sont que vous ne pouvez pas déduire l'entrée de la sortie sous une clé secrète et ni la sortie de l'entrée à l'insu de la clé. Cela ressemble beaucoup à la propriété unidirectionnelle des fonctions de hachage, mais la différence réside dans le fait qu'avec des valeurs d'entropie faibles comme les mots de passe, vous pouvez effectivement énumérer toutes les valeurs possibles et calculer les images sous la fonction de hachage publique et ainsi trouver la valeur dont l'image correspond à la pré-image. Avec une fonction pseudo aléatoire, vous ne pouvez pas le faire sans la clé (c'est-à-dire sans le poivre) car vous ne pouvez même pas calculer l'image d'une seule valeur sans la clé.
Le rôle important du $salt
Dans ce paramètre entre en jeu si vous avez accès à la base de données pendant une période prolongée et que vous pouvez toujours normalement travailler avec l'application de l'extérieur. Sans $salt
, Vous pouvez définir le mot de passe d'un compte que vous contrôlez sur une valeur connue $passwordKnown
Et comparer le hachage au mot de passe d'un mot de passe inconnu $passwordSecret
. En tant que hash($pepper . $passwordKnown)==hash($pepper . $passwordSecret)
si et seulement si $passwordKnown==$passwordSecret
Vous pouvez comparer un mot de passe inconnu avec n'importe quelle valeur choisie (en tant que technicité, j'assume la résistance aux collisions de la fonction de hachage). Mais avec le sel, vous obtenez hash($pepper . $salt1 . $passwordKnown)==hash($pepper . $salt2 . $passwordSecret)
si et seulement si $salt1 . $passwordKnown == $salt2 . $passwordSecret
Et que $salt1
Et $salt2
Ont été choisis au hasard pour $passwordKnown
Et respectivement $passwordSecret
Les sels ne seront plus jamais les mêmes (en supposant des valeurs aléatoires suffisamment grandes comme 256 bits) et vous ne pourrez donc plus comparer les mots de passe les uns avec les autres.
(Remarque: l'utilisation d'un sel ne représente que la moitié du travail; vous devez également ralentir la fonction de hachage - afin qu'il soit toujours difficile d'attaquer un seul mot de passe à faible entropie. La lenteur est généralement obtenue via plusieurs itérations ou hachage de la concaténation de 10000 copies du sel et du mot de passe.)
Ce que votre "poivre" fait, c'est qu'il transforme le hachage en MAC . Faire un bon MAC sécurisé à partir d'une fonction de hachage n'est pas facile, il vaut donc mieux utiliser HMAC au lieu d'une construction maison (la façon théorique de mettre c'est qu'une fonction de hachage résistante aux collisions n'est pas nécessairement indiscernable d'un Oracle aléatoire).
Avec un MAC, vous pouvez gagner en sécurité dans le sens suivant: peut-être, l'accès en lecture à la base de données par l'attaquant pourrait cesser d'être un vrai problème. La clé MAC (le "poivre") peut concentrer le besoin de confidentialité. Cependant, cela repose sur le fait que le MAC est également une fonction à sens unique, qui est une propriété que vous obtiendrez de nombreuses constructions MAC (y compris HMAC) mais qui n'est pas vraiment garantie cryptographiquement (il existe des subtilités).
Le "poivre" implique que vous avez une clé à gérer, y compris un stockage sécurisé d'une manière qui résiste aux redémarrages. Une clé est petite et tient dans la RAM, mais, en raison des exigences de stockage, il n'est pas clair si elle améliore réellement la sécurité. Un attaquant qui peut lire l'intégralité de la base de données peut également lire l'intégralité du disque dur, y compris tout fichier "protégé". La petite taille de la clé peut permettre certaines configurations avancées, par exemple la clé étant stockée sur des cartes à puce qui sont utilisées au démarrage mais qui ne sont pas connectées par la suite. Pour résumer, le fait que le poivrage en vaille la peine dépend vraiment du contexte - sur une base générale, je le déconseille, afin d'éviter la complexité supplémentaire.
Je voudrais souligner ce qu'un poivre peut vraiment faire.
Comme les autres l'ont déjà souligné, l'ajout d'un poivre n'est qu'un avantage, tant que l'attaquant a accès aux valeurs de hachage dans la base de données, mais n'a aucun contrôle sur le serveur, et donc ne connaît pas le poivre. Ceci est typique de l'injection SQL, probablement l'une des attaques les plus utilisées, car elle est si facile à faire.
$hashValue = bcrypt('12345', $cost, $salt);
Vous pouvez obtenir ce mot de passe facilement avec une attaque par dictionnaire, même si vous avez correctement utilisé une fonction de dérivation de clé lente. Mettez les mots de passe les plus utilisés dans un dictionnaire et force brute avec ces mots de passe faibles. Il est très probable que nous trouvions le mot de passe dans (trop) de nombreux cas.
$hashValue = bcrypt('12345anm8e3M-83*2cQ1mlZaU', $cost, $salt);
Avec le poivre, le mot de passe faible s'allonge, il contient désormais des caractères spéciaux, et plus important encore, vous ne le trouverez dans aucun dictionnaire. Donc, tant que le piment reste secret, il le fait empêche les attaques par dictionnaire, dans ce cas, il peut protéger les mots de passe faibles.
Éditer:
Il existe un meilleur moyen d'ajouter une clé côté serveur que de l'utiliser comme poivre. Avec un poivre, un attaquant doit obtenir des privilèges supplémentaires sur le serveur pour obtenir la clé. Le même avantage que nous obtenons en calculant d'abord le hachage, puis en chiffrant le hachage avec la clé côté serveur (cryptage bidirectionnel). Cela nous donne la possibilité d'échanger la clé chaque fois que cela est nécessaire.
$hash = bcrypt($passwort, $salt);
$encryptedHash = encrypt($hash, $serverSideKey);
L'article sur l'invention du salage et des itérations, pour les mots de passe Unix ( Password Security: A Case History, Morris & Thompson, 1978 ), décrit également l'équivalent d'un poivre:
Les huit premiers caractères du mot de passe de l'utilisateur sont utilisés comme clé pour le DES; puis l'algorithme est utilisé pour crypter une constante. Bien que cette constante soit nulle pour le moment, elle est facilement accessible et peut être rendue dépendante de l'installation.
Je n'ai cependant pas entendu parler de son utilisation. Quelqu'un d'autre?
Juste un BTW, les nouvelles directives NIST Digital Idendity (Draft) recommandent fortement d'utiliser Pepper également:
https://pages.nist.gov/800-63-3/sp800-63b.html#sec5
5.1.1.2 Vérificateur des secrets mémorisés:
... Une fonction de hachage à clé (par exemple, HMAC [FIPS198-1]), avec la clé stockée séparément des authentificateurs hachés (par exemple, dans un module de sécurité matériel) DEVRAIT être utilisée pour résister davantage aux attaques de dictionnaire contre les authentificateurs hachés stockés.
Considérez ce scénario:
Je suis sur le point de pénétrer dans un site Web X à l'aide d'une injection SQL pour récupérer une liste d'utilisateurs, avec leurs hachages de mot de passe et leur sel. Supposons que le site Web X utilise également un poivre mondial.
Tout ce que je devrais faire serait d'enregistrer un utilisateur sur le site Web X avec un nom d'utilisateur et un mot de passe connus avant l'injection SQL. Je saurais alors, pour un enregistrement particulier de la base de données, le hachage du mot de passe, le mot de passe en texte brut, le sel (stocké en texte brut) et il serait banal pour moi de casser le poivre mondial sur la base de cet enregistrement .
Donc, vraiment, un poivre serait un moyen de ralentir un attaquant pour un temps de travail insignifiant. Ils n'auraient pas à forcer brutalement le mot de passe + sel + poivre, comme prévu, uniquement le poivre.
Ce qui précède est une forme de attaque en texte clair choisie. Tant que les attaquants connaissent l'algorithme (hash ()), la sortie ($ hashed_password) et toutes les entrées sauf une ("constantes" $ salt & $ password et "variable" $ pepper), ils peuvent "résoudre pour x "comme une équation d'algèbre linéaire (h = s + p + x == hsp = x), mais par force brute bien sûr. Rendre le piment plus long que 56 octets (448 bits), la limite de bcrypt, augmente le coût en temps et est aussi bon que bcrypt mais peut-être pas aussi bon que scrypt. Donc, tant que le poivre est suffisamment long, c'est une amélioration.
Je ne sais pas très bien comment un serveur pourrait masquer une constante de poivre globale, mais mon avis est que tôt ou tard un pirate informatique qui a pénétré le serveur trouvera comment capturer la valeur de poivre. Pour rendre une valeur de poivre totalement sécurisée, il faudrait du matériel spécial. Une façon de procéder serait d'utiliser une carte FPGA installée sur le serveur. Le FPGA contiendrait le code utilisé pour effectuer le hachage, y compris la valeur du poivre et tous les calculs de hachage se produisent à l'intérieur du FPGA. Avec le FPGA, la programmation peut être une fonction à sens unique. Le poivron peut être programmé mais aucune instruction ne peut être envoyée pour le lire. Le poivre serait stocké sur un morceau de papier enfermé dans un coffre-fort. Si le poivre est généré au moins 128 bits de façon aléatoire, il n'y aurait aucun moyen pratique de le déterminer.
Je ne sais pas dans quelle mesure cela serait pratique car cela augmenterait le coût du matériel du serveur.