Le problème qui se pose ici est essentiellement un problème d'entropie. Commençons donc par là :
Entropie par caractère
Le nombre de bits d'entropie par octet est le suivant :
-
Caractères hexadécimaux
- Bits : 4
- Valeurs : 16
- Entropie en 72 caractères : 288 bits
-
Alpha-Numérique
- Bits : 6
- Valeurs : 62
- L'entropie en 72 caractères : 432 bits
-
"Symboles "communs
- Bits : 6.5
- Valeurs : 94
- Entropie en 72 caractères : 468 bits
-
Octets complets
- Bits : 8
- Valeurs : 255
- L'entropie en 72 caractères : 576 bits
La façon dont nous agissons dépend donc du type de personnages que nous attendons.
Le premier problème
Le premier problème avec votre code, c'est que votre "poivre" L'étape du hachage produit des caractères hexagonaux (puisque le quatrième paramètre de la commande hash_hmac()
n'est pas défini).
Par conséquent, en hachant votre poivre, vous réduisez l'entropie maximale disponible pour le mot de passe d'un facteur 2 (de 576 à 288). possible bits).
Le deuxième problème
Cependant, sha256
ne prévoit que 256
d'entropie en premier lieu. Vous réduisez donc effectivement une possibilité de 576 bits à 256 bits. Votre étape de hachage * immédiate*, par définition, perd au moins 50 % de la possible l'entropie du mot de passe.
Vous pouvez résoudre partiellement ce problème en passant à SHA512
où l'entropie disponible ne serait réduite que d'environ 12 %. Mais cela reste une différence non négligeable. Ces 12 % réduisent le nombre de permutations d'un facteur de 1.8e19
. C'est un chiffre important... Et c'est le facteur il la réduit de ...
La question sous-jacente
Le problème sous-jacent est qu'il existe trois types de mots de passe de plus de 72 caractères. L'impact de ce système de style sur eux sera très différent :
Note : à partir de maintenant, je suppose que nous comparons avec un système de poivre qui utilise SHA512
avec une sortie brute (non hexadécimale).
-
Mots de passe aléatoires à haute entropie
Il s'agit de vos utilisateurs qui utilisent des générateurs de mots de passe qui génèrent ce qui s'apparente à de grandes clés pour les mots de passe. Ces mots de passe sont aléatoires (générés et non choisis par l'homme) et présentent une entropie élevée par caractère. Ces types de mots de passe utilisent un nombre élevé d'octets (caractères > 127) et certains caractères de contrôle.
Pour ce groupe, votre fonction de hachage de manière significative réduisent leur entropie disponible en bcrypt
.
Permettez-moi de le répéter. Pour les utilisateurs qui utilisent des mots de passe longs à forte entropie, votre solution est la suivante de manière significative réduit la force de leur mot de passe d'une quantité mesurable. (62 bits d'entropie perdus pour un mot de passe de 72 caractères, et davantage pour les mots de passe plus longs).
-
Mots de passe aléatoires à entropie moyenne
Ce groupe utilise des mots de passe contenant des symboles courants, mais pas d'octets élevés ni de caractères de contrôle. Il s'agit de mots de passe dactylographiables.
Pour ce groupe, vous allez légèrement débloquer plus d'entropie (pas la créer, mais permettre à plus d'entropie de tenir dans le mot de passe bcrypt). Quand je dis "légèrement", je veux dire "légèrement". Le seuil de rentabilité est atteint lorsque les 512 bits de SHA512 sont utilisés au maximum. Par conséquent, le pic se situe à 78 caractères.
Permettez-moi de le répéter. Pour cette catégorie de mots de passe, vous ne pouvez stocker que 6 caractères supplémentaires avant de manquer d'entropie.
-
Mots de passe non aléatoires à faible entropie
Il s'agit du groupe qui utilise des caractères alphanumériques qui ne sont probablement pas générés de manière aléatoire. Quelque chose comme une citation biblique ou autre. Ces phrases ont environ 2,3 bits d'entropie par caractère.
Pour ce groupe, vous pouvez débloquer significativement plus d'entropie (pas la créer, mais permettre d'en mettre plus dans l'entrée du mot de passe bcrypt) par le hachage. Le seuil de rentabilité se situe autour de 223 caractères avant que l'entropie ne soit épuisée.
Répétons-le. Pour cette catégorie de mots de passe, le pré-hachage augmente incontestablement la sécurité de manière significative.
Retour au monde réel
Ces calculs d'entropie n'ont pas beaucoup d'importance dans le monde réel. Ce qui compte, c'est de deviner l'entropie. C'est ce qui affecte directement ce que les attaquants peuvent faire. C'est ce que vous voulez maximiser.
Bien que peu de recherches aient été menées sur l'estimation de l'entropie, j'aimerais souligner certains points.
Les chances de deviner au hasard 72 caractères corrects d'affilée sont les suivantes extrêmement faible. Vous avez plus de chances de gagner 21 fois à la loterie Powerball que d'avoir cette collision... C'est la taille du chiffre dont nous parlons.
Mais il se peut que nous ne tombions pas dessus statistiquement. Dans le cas des phrases, la probabilité que les 72 premiers caractères soient identiques est beaucoup plus élevée que pour un mot de passe aléatoire. Mais elle reste trivialement faible (vous avez plus de chances de gagner 5 fois à la loterie Powerball, sur la base de 2,3 bits par caractère).
Pratiquement
En pratique, cela n'a pas vraiment d'importance. Les chances que quelqu'un devine correctement les 72 premiers caractères, alors que les derniers font une différence significative, sont si faibles qu'il n'y a pas lieu de s'en préoccuper. Pourquoi ?
Disons que vous prenez une phrase. Si la personne parvient à trouver les 72 premiers caractères, elle est soit vraiment chanceux (peu probable), ou bien il s'agit d'une expression courante. S'il s'agit d'une phrase courante, la seule variable est la durée de la fabrication.
Prenons un exemple. Prenons une citation de la Bible (uniquement parce qu'il s'agit d'une source courante de textes longs, et pour aucune autre raison) :
Tu ne convoiteras pas la maison de ton prochain. Tu ne convoiteras pas la femme de ton prochain, ni son serviteur ou sa servante, ni son boeuf ou son âne, ni rien de ce qui appartient à ton prochain.
Cela représente 180 caractères. Le 73e caractère est le g
dans la deuxième neighbor's
. Si vous avez deviné autant, il est probable que vous ne vous êtes pas arrêté à nei
mais en continuant avec le reste du verset (puisque c'est ainsi que le mot de passe est susceptible d'être utilisé). Par conséquent, votre "hachage" n'apporte pas grand-chose.
BTW : je ne préconise ABSOLUMENT PAS l'utilisation d'une citation de la Bible. En fait, c'est exactement le contraire.
Conclusion
Vous n'aiderez pas vraiment les personnes qui utilisent des mots de passe longs en procédant d'abord à un hachage. Vous pouvez certainement aider certains groupes. Pour d'autres, c'est le contraire qui est vrai.
Mais en fin de compte, rien de tout cela n'est très significatif. Les chiffres dont il est question sont simplement WAY trop élevé. La différence d'entropie ne sera pas très importante.
Il vaut mieux laisser bcrypt tel quel. Il est plus probable que vous fassiez une erreur de hachage (littéralement, vous l'avez déjà fait, et vous n'êtes ni le premier, ni le dernier à faire cette erreur) que l'attaque que vous essayez d'empêcher ne se produise.
Concentrez-vous sur la sécurisation du reste du site. Et ajoutez un compteur d'entropie de mot de passe à la boîte de mot de passe lors de l'enregistrement pour indiquer la force du mot de passe (et indiquer si un mot de passe est trop long que l'utilisateur peut souhaiter le changer)...
C'est du moins mon 0,02 $ (ou peut-être bien plus que 0,02 $)...
En ce qui concerne l'utilisation d'un poivre "secret" :
Il n'y a littéralement aucune recherche sur l'intégration d'une fonction de hachage dans bcrypt. Par conséquent, il est difficile de savoir si l'introduction d'un hachage "poivré" dans bcrypt entraînera des vulnérabilités inconnues (nous savons que l'introduction d'un hachage "poivré" dans bcrypt entraînera des vulnérabilités inconnues). hash1(hash2($value))
peut révéler des vulnérabilités importantes en ce qui concerne la résistance aux collisions et les attaques par préimage).
Étant donné que vous envisagez déjà de stocker une clé secrète (le "poivre"), pourquoi ne pas l'utiliser d'une manière bien étudiée et comprise ? Pourquoi ne pas crypter le hachage avant de le stocker ?
En fait, après avoir haché le mot de passe, vous introduisez l'ensemble du résultat dans un algorithme de cryptage puissant. Stockez ensuite le résultat chiffré.
Or, une attaque par injection SQL n'entraînera aucune fuite utile, car elle ne dispose pas de la clé de chiffrement. Et si la clé est divulguée, les attaquants ne sont pas mieux lotis que si vous aviez utilisé un hachage simple (qui peut être prouvé, ce que le poivre "pre-hash" ne fournit pas).
Note : si vous choisissez de faire cela, utilisez une bibliothèque. Pour PHP, je fortement recommande l'utilisation de Zend Framework 2 Zend\Crypt
l'emballage. C'est en fait le seul que je recommanderais à l'heure actuelle. Il a fait l'objet d'un examen approfondi et prend toutes les décisions à votre place (ce qui est une très bonne chose)...
Quelque chose comme :
use Zend\Crypt\BlockCipher;
public function createHash($password) {
$hash = password_hash($password, PASSWORD_BCRYPT, ["cost"=>$this->cost]);
$blockCipher = BlockCipher::factory('mcrypt', array('algo' => 'aes'));
$blockCipher->setKey($this->key);
return $blockCipher->encrypt($hash);
}
public function verifyHash($password, $hash) {
$blockCipher = BlockCipher::factory('mcrypt', array('algo' => 'aes'));
$blockCipher->setKey($this->key);
$hash = $blockCipher->decrypt($hash);
return password_verify($password, $hash);
}
Et c'est bénéfique parce que vous utilisez tous les algorithmes d'une manière qui est bien comprise et bien étudiée (relativement du moins). N'oubliez pas :
N'importe qui, de l'amateur le plus ignorant au meilleur cryptographe, peut créer un algorithme qu'il ne peut pas lui-même casser.
3 votes
Blowfish n'est pas le seul à tronquer le mot de passe, faisant croire à tort qu'il est plus sûr qu'il ne l'est en réalité. Voici un histoire intéressante de la limite de 8 caractères.
2 votes
La troncature de 72 caractères est-elle fondamentale pour l'algorithme Blowfish, ou seulement pour l'implémentation PHP ? IIRC Blowfish est également utilisé sur (au moins quelques) 'nixes pour crypter les mots de passe des utilisateurs.
3 votes
Le problème concerne Bcrypt, et non Blowfish. Je peux reproduire ce problème avec Python et Bcrypt uniquement.
0 votes
@Blender : Merci pour votre commentaire et votre travail. Je n'ai pas trouvé de fonctions différentes en php pour blowfish et bcrypt et j'ai pensé que c'était la même chose. Mais est-ce que cela ne fait aucune différence pour moi en php ? Je préférerais utiliser la fonction standard de php.
0 votes
Douglas, oui, la limite de 72 caractères est fondamentale pour BCrypt. Vous pourriez l'étendre (le cryptage DES étendu le fait par rapport au DES standard, par exemple), mais ce ne serait pas standard.
1 votes
Voir aussi la page Cadre de hachage de mots de passe en PHP (PHPass). Il est portable et renforcé contre un certain nombre d'attaques courantes sur les mots de passe des utilisateurs. L'auteur du framework (SolarDesigner) est le même que celui qui a écrit John l'Éventreur et siège en tant que juge au sein de la Concours de déchiffrage de mots de passe . Il s'y connaît donc en matière d'attaques contre les mots de passe.
0 votes
Bcrypt utilise l'algorithme Blowfish pour hacher les mots de passe. Vous ne pouvez donc pas utiliser bcrypt indépendamment de Blowfish.