Comment hachez les mots de passe longs (>72 caractères) avec blowfish

la dernière semaine, j'ai lu beaucoup d'articles sur le hachage de mot de passe et Blowfish semble être (un de) le meilleur algorithme de hachage en ce moment - mais ce n'est pas le sujet de cette question!

la limite des 72 caractères

Blowfish considérer seulement les 72 premiers caractères du mot de passe saisi:

php prettyprint-override"><?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));
?>

la sortie est:

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 voir, seuls les 72 premiers caractères comptent. Twitter utilise blowfish alias bcrypt pour stocker leurs mots de passe ( https://shouldichangemypassword.com/twitter-hacked.php ) et devinez quoi: changez votre mot de passe twitter en un long mot de passe avec plus de 72 caractères et vous pouvez vous connecter à votre compte en entrant seulement les 72 premiers caractères.

Blowfish et Poivre

il y a beaucoup d'opinions différentes sur les mots de passe" peppering". Certaines personnes disent que c'est inutile, parce que vous avez pour supposer que la corde de poivre secrète est également connu/publié de sorte qu'il n'améliore pas le hash. J'ai un serveur de base de données séparé donc il est tout à fait possible que seule la base de données soit divulguée et pas le pepper constant.

dans ce cas (poivre non divulgué) vous rendez une attaque basée sur un dictionnaire plus difficile (corrigez-moi si ce n'est pas juste). Si votre corde de poivre est aussi fuité: pas si mal - vous avez toujours le sel et il est aussi bon protégé qu'un hash sans poivre.

donc je pense que peppering le mot de passe n'est pas un mauvais choix.

Suggestion

ma suggestion pour obtenir un hachage Blowfish pour un mot de passe avec plus de 72 caractères (et poivre) est:

<?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 façon la plus sûre? Obtenir un SHA-256 hachage d'abord (qui renvoie 64 caractères) ou ne considérer que les 72 premiers caractères du mot de passe?

Pros

  • l'utilisateur ne peut pas se connecter en entrant seulement les 72 premiers caractères
  • vous pouvez ajouter le poivre sans dépasser la limite de caractère
  • La sortie de hash_hmac aurait probablement plus d'entropie que le mot de passe
  • le mot de passe est hachuré par deux fonctions différentes

Cons

  • seulement 64 caractères sont utilisés pour construire le hachage de poisson-lune



Edit 1: This question addresses only the PHP integration of blowfish/bcrypt. Merci pour les commentaires!

82
demandé sur Community 2013-05-16 22:17:02

3 réponses

le problème 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:

  • Caractères Hex
    • Bits: 4
    • valeurs: 16
    • entropie en 72 caractères: 288 bits
  • Alpha-Numérique
    • Bits: 6
    • valeurs: 62
    • entropie en 72 caractères: 432 bits
  • "Commune" Symboles
    • Bits: 6.5
    • Valeurs: 94
    • entropie en 72 caractères: 468 bits
  • Full Bytes
    • Bits: 8
    • valeurs: 255
    • entropie en 72 caractères: 576 bits

ainsi, la façon dont nous agissons dépend du type de caractères que nous attendons.

Le Premier Problème

le premier problème avec votre code, est que votre " pepper " étape de hachage sort des caractères hexadécimaux (depuis le quatrième paramètre de hash_hmac() n'est pas défini).

donc, en hashant votre poivre, vous coupez effectivement l'entropie maximum disponible au mot de passe par un facteur de 2 (de 576 à 288 possible bits).

Le Second Problème

cependant, sha256 ne fournit 256 bits d'entropie en premier lieu. Donc vous coupez effectivement un possible 576 bits vers le bas à 256 bit. Votre étape de hachage * immédiatement*, par définition perd au moins 50% du possible entropie dans le mot de passe.

vous pourriez résoudre partiellement ce problème en passant à SHA512 , où vous ne réduiriez l'entropie disponible que d'environ 12%. Mais ce n'est toujours pas une différence insignifiante. Ce 12% réduit le nombre de permutations d'un facteur 1.8e19 . C'est un grand nombre... Et c'est la facteur il le 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 que ce système de style aura sur eux sera très différent:

Note: à partir de Maintenant je suppose que nous comparons à un système de poivre qui utilise SHA512 avec la production brute (pas hex).

  • Haute entropie des mots de passe aléatoires

    ce sont vos utilisateurs utilisant des générateurs de mot de passe qui génèrent ce qui revient à de grandes clés pour les mots de passe. Ils sont aléatoires (générés, pas choisis par l'homme), et ont une entropie élevée par caractère. Ces types utilisent des octets élevés (caractères > 127) et certains caractères de contrôle.

    pour ce groupe, votre fonction de hachage réduira de manière significative leur entropie disponible en bcrypt .

    laissez-moi le redire. Pour les utilisateurs qui utilisent une entropie élevée, des mots de passe longs, votre solution réduit" de manière significative 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 plus pour des mots de passe plus longs)

  • Moyenne de l'entropie des mots de passe aléatoires

    ce groupe utilise des mots de passe contenant des symboles communs, mais aucun haut octets ou caractères de contrôle. Ce sont vos mots de passe dactylographiables.

    pour ce groupe, vous allez légèrement déverrouiller plus d'entropie (ne pas la créer, mais permettre plus d'entropie pour s'insérer dans le mot de passe bcrypt). Quand je dis légèrement, je veux dire légèrement. Le seuil de rentabilité se produit lorsque vous maxez les 512 bits que SHA512 a. Par conséquent, le pic est à 78 caractères.

    laissez-moi le redire. Pour cette classe de mots de passe, vous ne pouvez stockez 6 caractères supplémentaires avant de manquer d'entropie.

  • Faible entropie non-aléatoire de mots de passe

    il s'agit du groupe qui utilise des caractères alphanumériques qui ne sont probablement pas générés au hasard. Quelque chose comme une citation de la bible ou autre. Ces phrases ont environ 2,3 bits d'entropie par caractère.

    pour ce groupe, vous pouvez débloquer de manière significative plus d'entropie (ne pas créer, mais permettre à more de s'insérer dans l'entrée de mot de passe bcrypt) par le hachage. Le seuil de rentabilité est d'environ 223 caractères avant de manquer d'entropie.

    disons-le encore. Pour cette classe de mots de passe, le pré-hachage augmente la sécurité de manière significative.

De Retour Dans Le Monde Réel

ces types de calculs d'entropie n'ont pas vraiment d'importance dans le monde réel. Ce qui compte, c'est deviner l'entropie. C'est quels effets directement ce que les attaquants peuvent faire. C'est ce que vous souhaitez optimiser.

bien qu'il y ait peu de recherches sur l'entropie, il y a des points que j'aimerais souligner.

les chances de deviner au hasard 72 caractères corrects dans une rangée sont extrêmement faible. Vous êtes plus susceptible de gagner la loterie Powerball 21 fois, que d'avoir cette collision... C'est la façon dont un grand nombre nous parlons sur.

mais nous ne pouvons pas tomber sur elle statistiquement. Dans le cas de 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 il est encore trivialement bas (vous êtes plus susceptible de gagner la loterie Powerball 5 fois, basé sur 2,3 bits par personnage).

pratiquement

pratiquement, ça n'a pas vraiment d'importance. Les chances de quelqu'un deviner les 72 premiers caractères droit, là où ces derniers font une différence significative sont si faibles qu'il ne vaut pas la peine de s'inquiéter. Pourquoi?

disons que vous prenez une phrase. Si la personne peut obtenir les 72 premiers caractères droite, ils sont soit vraiment chanceux (peu probable), ou c'est une phrase commune. Si c'est une expression courante, la seule variable est combien de temps pour le faire.

prenons un exemple. Prenons une citation de la bible (juste parce que c'est un source commune de texte long, pas pour d'autres raisons):

tu ne convoiteras pas la maison de ton prochain. Tu ne convoiteras pas la femme de ton prochain, ni son serviteur ou servante, son bœuf ou un âne, ni aucune chose qui appartienne à ton prochain.

ça fait 180 caractères. Le 73ème caractère est le g dans le second neighbor's . Si vous avez deviné cela, vous ne vous arrêtez probablement pas à nei , mais continuer avec le reste du verset (puisque c'est ainsi que le mot de passe est susceptible d'être utilisé). Par conséquent, votre "hash" n'a pas ajouté beaucoup.

BTW: Je ne recommande absolument pas d'utiliser une citation de la bible. En fait, l'exact opposé.

Conclusion

vous n'allez pas vraiment aider les gens qui utilisent de longs mots de passe en les hachant en premier. Certains groupes, vous pouvez certainement aider. Vous pouvez certainement faire de mal.

Mais en fin de compte, rien de tout cela est trop importante. Les chiffres que nous traitons sont juste CHEMIN trop élevé. La différence d'entropie n'est pas beaucoup.

vous feriez mieux de quitter bcrypt. Vous êtes plus susceptibles à visser le hachage (littéralement, vous l'avez déjà fait, et vous n'êtes pas le premier, ou le dernier à commettre cette erreur) que l'attaque que vous essayez d'éviter, va arriver.

mettre L'accent sur la sécurisation le reste du site. Et Ajouter un entropymètre 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 superposé que l'utilisateur peut souhaiter le changer)...

C'est mon 0,02 $au moins (ou peut-être beaucoup plus que 0,02$)...

En Ce Qui Concerne L'Utilisation D'Un Poivre" Secret":

il n'y a littéralement aucune recherche pour alimenter une fonction de hachage dans bcrypt. Par conséquent, il n'est pas clair au mieux si l'introduction d'un hachage" pété "dans bcrypt ne provoquera jamais de vulnérabilités inconnues (nous savons que faire hash1(hash2($value)) peut exposer des vulnérabilités significatives autour de la résistance aux collisions et des attaques de préimage).

considérant que vous envisagez déjà de stocker une clé secrète (le "poivre"), pourquoi ne pas l'utiliser d'une manière qui est bien étudiée et comprise? Pourquoi ne pas crypter le hachage avant de le stocker?

en gros, après que vous hachez le mot de passe, toute la sortie de hachage dans un algorithme de cryptage fort. Puis stocker le résultat chiffré.

maintenant, une attaque par injection SQL ne fera pas fuiter quoi que ce soit d'utile, parce qu'ils n'ont pas la clé de chiffrement. Et si la clé est divulguée, les attaquants ne sont pas mieux lotis que si vous avez utilisé un simple hash (ce qui est prouvable, quelque chose avec le poivre "pré-hash" ne fournit pas).

Note: Si vous choisissez de faire cela, utilisez une bibliothèque. Pour PHP, Je fortement recommande le paquet Zend\Crypt de Zend Framework 2. C'est la seule que je recommande à ce moment-ci. Il a été fortement revu, et il prend toutes les décisions pour vous (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 au moins). Rappelez-vous:

N'importe qui, de l'amateur le plus ignorant au meilleur cryptographe, peut créer un algorithme qu'il lui-même ne peut pas briser.

126
répondu ircmaxell 2018-09-30 17:09:22

les mots de passe Peppering est sûrement une bonne chose à faire, mais voyons pourquoi.

nous devrions d'abord répondre à la question quand exactement un poivre aide. Le poivre seulement protège les mots de passe, tant qu'il reste secret, de sorte que si un attaquant a accès au serveur lui-même, il n'est d'aucune utilité. Une attaque beaucoup plus facile est SQL-injection, qui permet l'accès en lecture à la base de données (à nos valeurs de hachage), j'ai préparé un démo de SQL-injection pour montrer comment facile il peut l'être (Cliquez sur la flèche suivante pour obtenir une entrée préparée).

alors qu'est-ce que le poivre aide vraiment? Aussi longtemps que le poivre reste secret, il protège les mots de passe faibles d'une attaque de dictionnaire. Le mot de passe 1234 deviendra alors quelque chose comme 1234-p*deDIUZeRweretWy+.O . Ce mot de passe est non seulement beaucoup plus long, il contient également des caractères spéciaux et ne sera jamais partie d'aucun dictionnaire.

maintenant nous pouvons estimer quels mots de passe nos utilisateurs utiliseront, probablement plus d'utilisateurs vont entrer des mots de passe faibles, comme il ya des utilisateurs avec des mots de passe entre 64-72 caractères (en fait, ce sera très rare).

un autre point est la plage de forçage Brutal. La fonction de hachage sha256 retournera 256 bits de sortie ou 1.2e77 combinaisons, c'est beaucoup trop pour le forçage Brutal, même pour les GPU (si j'ai calculé correctement, cela aurait besoin d'environ 2E61 ans sur un GPU en 2013). Nous n'avons donc pas de réel inconvénient à appliquer les poivrer. Parce que les valeurs de hachage ne sont pas systématiques, vous ne pouvez pas accélérer le forçage brutal avec des modèles communs.

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 ce .

P. P. S je pense que votre exemple est défectueux, vous ne pouvez pas générer le hachage avec la pleine longueur de mot de passe, et de vérifier avec tronqué. Tu voulais probablement appliquer le poivre de la même façon. mode de génération du hachage et de vérification du hachage.

5
répondu martinstoeckli 2017-05-23 12:34:14

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

la limite de mot de passe de 56 octets recommandée (y compris l'octet de terminaison nulle) pour bcrypt se rapporte à la limite de 448 bits de la clé Blowfish. Les octets au-delà de cette limite ne sont pas complètement mélangés dans le hachage résultant. La limite absolue de 72 octets sur les mots de passe bcrypt est donc moins pertinente lorsque 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 de plus de 55 octets de longueur, rappelez-vous que vous pouvez toujours augmenter les cycles d'étirement du mot de passe à la place, pour augmenter la sécurité dans le cas d'une violation de la table de mot de passe (bien que cela doit être beaucoup par rapport à 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 massivement long, alors l'expiration du mot de passe devrait également être courte, comme 2 semaines. Cela signifie qu'un mot de passe est beaucoup moins susceptible de rester valide alors qu'un hacker investit leurs ressources à vaincre le facteur de travail impliqué dans le test de chaque mot de passe d'essai pour voir si elle produira un hachage correspondant.

bien sûr, dans le cas où la table des mots de passe n'est pas brisée, nous ne devrions permettre aux pirates, au plus, dix tentatives de 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é-hachage un mot de passe qui est plus long que 55 octets, vous devez utiliser SHA-384, car il a la plus grande sortie sans dépasser la limite.

2
répondu Phil 2017-02-13 12:31:40