93 votes

Comment hacher des mots de passe longs (>72 caractères) avec blowfish

La semaine dernière, j'ai lu de nombreux articles sur le hachage de mots de passe et Blowfish semble être (l'un des) meilleurs algorithmes de hachage à l'heure actuelle - mais ce n'est pas le sujet de cette question !

La limite de 72 caractères

Blowfish ne prend en compte que les 72 premiers caractères du mot de passe saisi :

<?php
$password = "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)";
$hash = password_hash($password, PASSWORD_BCRYPT);
var_dump($password);

$input = substr($password, 0, 72);
var_dump($input);

var_dump(password_verify($input, $hash));
?>

Le résultat est le suivant :

string(119) "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)"
string(72) "Wow. This is a super secret and super, super long password. Let's add so"
bool(true)

Comme vous pouvez le constater, seuls les 72 premiers caractères comptent. Twitter utilise blowfish aka bcrypt pour stocker ses mots de passe ( https://shouldichangemypassword.com/twitter-hacked.php ) et devinez quoi : changez votre mot de passe Twitter en un mot de passe long de plus de 72 caractères et vous pourrez vous connecter à votre compte en saisissant uniquement les 72 premiers caractères.

Poisson-globe et poivre

Il y a beaucoup d'opinions différentes sur le fait de "poivrer" les mots de passe. Certains disent que ce n'est pas nécessaire, parce qu'il faut supposer que la chaîne secrète de piment est également connue/publiée et qu'elle n'améliore donc pas le hachage. J'ai un serveur de base de données séparé, il est donc tout à fait possible que seule la base de données soit divulguée et non la chaîne secrète.

Dans ce cas (le poivre ne fuit pas), vous rendez plus difficile une attaque basée sur un dictionnaire (corrigez-moi si ce n'est pas correct). Si votre chaîne de poivre est également divulguée : ce n'est pas si grave - vous avez toujours le sel et la protection est aussi bonne que celle d'un hachage sans poivre.

Je pense donc que l'utilisation du mot de passe n'est pas un mauvais choix.

Suggestion

Ma suggestion pour obtenir un hachage Blowfish pour un mot de passe de plus de 72 caractères (et du poivre) est la suivante :

<?php
$pepper = "foIwUVmkKGrGucNJMOkxkvcQ79iPNzP5OKlbIdGPCMTjJcDYnR";

// Generate Hash
$password = "Wow. This is a super secret and super, super long password. Let's add some special ch4r4ct3rs a#d everything is fine :)";
$password_peppered = hash_hmac('sha256', $password, $pepper);
$hash = password_hash($password_peppered, PASSWORD_BCRYPT);

// Check
$input = substr($password, 0, 72);
$input_peppered = hash_hmac('sha256', $input, $pepper);

var_dump(password_verify($input_peppered, $hash));
?>

Ceci est basé sur cette question : password_verify retour false .

La question

Quelle est la solution la plus sûre ? Obtenir d'abord un hachage SHA-256 (qui renvoie 64 caractères) ou ne prendre en compte que les 72 premiers caractères du mot de passe ?

Pour

  • L'utilisateur ne peut pas se connecter en saisissant uniquement les 72 premiers caractères.
  • Vous pouvez ajouter le poivre sans dépasser la limite de caractères
  • La sortie de hash_hmac aurait probablement plus d'entropie que le mot de passe lui-même
  • Le mot de passe est haché par deux fonctions différentes

Cons

  • Seuls 64 caractères sont utilisés pour construire le hachage Blowfish.

Editer 1 : Cette question ne concerne que l'intégration en PHP de blowfish/bcrypt. Merci pour les commentaires !

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.

141voto

ircmaxell Points 74865

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.

6 votes

Merci beaucoup pour cette réponse détaillée. Cela m'aide vraiment !

1 votes

Mes compliments pour cette réponse. Un petit pinaillage cependant, c'est la grande majorité des utilisateurs qui utilisent des mots de passe très faibles, des mots et dérivés contenus dans un dictionnaire pour craquer les mots de passe, un poivre les protègerait indépendamment des questions d'entrophie. Pour éviter de perdre l'entrophie, vous pourriez simplement concaténer le mot de passe et le poivre. Cependant, votre suggestion de crypter la valeur hash est probablement la meilleure solution pour ajouter un secret côté serveur.

2 votes

@martinstoeckli : Mon problème avec le concept de poivre n'est pas dans sa valeur. C'est le fait que l'application du "poivre" entre en territoire inconnu en termes d'algorithmes cryptographiques. Ce n'est pas une bonne chose. Je pense plutôt que les primitives cryptographiques devraient être combinées de la manière dont elles ont été conçues pour aller ensemble. En fait, le concept de base d'un "pepper" sonne à mes oreilles comme ce qu'ont dit certaines personnes qui ne connaissaient rien à la cryptographie "Plus de hachages, c'est mieux ! Nous avons du sel, du poivre c'est bien aussi !" . Je préférerais une implémentation plus simple, plus testée et plus directe.

5voto

martinstoeckli Points 6953

Le pimentage des mots de passe est certainement une bonne chose à faire, mais voyons pourquoi.

Il convient tout d'abord de répondre à la question de savoir quand un poivre est utile. Le poivre ne protège que les mots de passe, tant qu'il reste secret, donc si un attaquant a accès au serveur lui-même, il n'est d'aucune utilité. Une attaque beaucoup plus facile est l'injection SQL, qui permet l'accès en lecture à la base de données (à nos valeurs de hachage), c'est-à-dire que l'on prépare une Démonstration de l'injection SQL pour montrer à quel point cela peut être facile (cliquez sur la flèche suivante pour obtenir une entrée préparée).

Alors, à quoi sert le poivre ? Tant que le poivre reste secret, il protège les mots de passe faibles contre une attaque par dictionnaire. Le mot de passe 1234 deviendrait alors quelque chose comme 1234-p*deDIUZeRweretWy+.O . Ce mot de passe est non seulement beaucoup plus long, mais il contient également des caractères spéciaux et ne fera jamais partie d'un dictionnaire.

Nous pouvons maintenant estimer les mots de passe que nos utilisateurs utiliseront. Il est probable que davantage d'utilisateurs entreront des mots de passe faibles, car certains utilisateurs ont des mots de passe de 64 à 72 caractères (en fait, c'est très rare).

Un autre point est la plage de forçage brutal. La fonction de hachage sha256 renvoie 256 bits en sortie, soit 1,2E77 combinaisons, ce qui est beaucoup trop pour le brute-forcing, même pour les GPU (si j'ai bien calculé, il faudrait à peu près 2E61 ans sur un GPU en 2013). Nous n'avons donc pas de réel désavantage à appliquer le poivre. Les valeurs de hachage n'étant pas systématiques, il n'est pas possible d'accélérer le forçage brutal à l'aide de motifs courants.

P.S. Pour autant que je sache, la limite de 72 caractères est spécifique à l'algorithme de BCrypt lui-même. La meilleure réponse que j'ai trouvée est cette .

P.P.S Je pense que votre exemple est erroné, vous ne pouvez pas générer le hachage avec la longueur complète du mot de passe et le vérifier avec un mot de passe tronqué. Vous vouliez probablement appliquer le poivre de la même manière pour générer le hachage et pour le vérifier.

0 votes

En ce qui concerne votre P.P.S., je peux simplement dire : Oui, il peut vérifier le mot de passe tronqué avec le hachage du mot de passe non tronqué et obtenir quand même true . C'est l'objet de cette question. Jetez-y un coup d'œil vous-même : viper-7.com/RLKFnB

0 votes

@Panique - Le problème n'est pas le calcul du hash BCrypt, c'est le HMAC avant. Pour générer le hachage SHA, l'OP utilise le mot de passe complet et utilise le résultat comme entrée pour BCrypt. Pour la vérification, il tronque le mot de passe avant de calculer le hachage SHA, puis utilise ce résultat complètement différent comme entrée pour BCrypt. Le HMAC accepte des données de n'importe quelle longueur.

2voto

Phil Points 666

Bcrypt utilise un algorithme basé sur le coûteux algorithme de configuration de clé Blowfish.

La limite de 56 octets du mot de passe recommandé (y compris l'octet de terminaison nul) pour bcrypt correspond à la limite de 448 bits de la clé Blowfish. Tout octet au-delà de cette limite n'est pas entièrement mélangé dans le hachage résultant. La limite absolue de 72 octets pour les mots de passe bcrypt est donc moins pertinente si l'on considère l'effet réel de ces octets sur le hachage résultant.

Si vous pensez que vos utilisateurs choisiraient normalement des mots de passe d'une longueur supérieure à 55 octets, n'oubliez pas que vous pouvez toujours augmenter le nombre de tours d'étirement du mot de passe, afin d'accroître la sécurité en cas de violation de la table des mots de passe (bien que ce soit beaucoup plus que l'ajout de caractères supplémentaires). Si les droits d'accès des utilisateurs sont si critiques que les utilisateurs auraient normalement besoin d'un mot de passe extrêmement long, l'expiration du mot de passe devrait également être courte, par exemple 2 semaines. Cela signifie qu'un mot de passe a beaucoup moins de chances de rester valide pendant qu'un pirate informatique investit ses ressources pour vaincre le facteur de travail impliqué dans le test de chaque mot de passe d'essai pour voir s'il produira un hachage correspondant.

Bien sûr, dans le cas où la table des mots de passe n'est pas violée, nous ne devrions permettre aux pirates informatiques que dix tentatives au maximum pour deviner le mot de passe de 55 octets d'un utilisateur, avant de verrouiller le compte de l'utilisateur ;)

Si vous décidez de pré-hacher un mot de passe de plus de 55 octets, vous devez utiliser SHA-384, car c'est celui qui produit le plus grand nombre d'octets sans dépasser la limite.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X