Quel type / longueur de colonne dois-je utiliser pour stocker un mot de passe haché Bcrypt dans une base de données?

318

Je souhaite stocker un mot de passe haché (à l'aide de BCrypt) dans une base de données. Quel serait un bon type pour cela, et quelle serait la bonne longueur? Les mots de passe hachés avec BCrypt sont-ils toujours de la même longueur?

ÉDITER

Exemple de hachage:

$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu

Après avoir haché certains mots de passe, il semble que BCrypt génère toujours 60 hachages de caractères.

EDIT 2

Désolé de ne pas avoir mentionné l'implémentation. J'utilise jBCrypt .

méthode d'aide
la source
Voir également le framework de hachage de mot de passe PHP d'Openwall (PHPass). Son portable et renforcé contre un certain nombre d'attaques courantes contre les mots de passe des utilisateurs. Le gars qui a écrit le framework (SolarDesigner) est le même que celui qui a écrit John The Ripper et siège en tant que juge dans le concours de hachage de mot de passe . Il sait donc une chose ou deux sur les attaques de mots de passe.
2014
1
Si quelqu'un tombe dessus à la recherche d'une solution pour scrypt : la réponse de Gumbo s'applique également à scrypt. J'ai personnellement appliqué BINARY (64) dans MySQL et cela m'a permis de tester l'égalité d'octets sous Python plus tard.
Philippe Hebert

Réponses:

370

Le format de cryptage modulaire pour bcrypt se compose de

  • $2$, $2a$ou $2y$identifier l' algorithme et le format de hachage
  • une valeur à deux chiffres indiquant le paramètre de coût, suivie de $
  • a 53 caractères valeur codée en base 64 (ils utilisent l'alphabet ., /, 0- 9, A- Z, a- zqui est différente de la norme de codage de base 64 alphabet) consistant en:
    • 22 caractères de sel (en fait seulement 128 bits sur les 132 bits décodés)
    • 31 caractères de sortie cryptée (effectivement seulement 184 bits sur les 186 bits décodés)

Ainsi, la longueur totale est respectivement de 59 ou 60 octets.

Lorsque vous utilisez le format 2a, vous aurez besoin de 60 octets. Et donc pour MySQL je recommande d'utiliser le CHAR(60) BINARYouBINARY(60) (voir le _bin et binaires classements pour des informations sur la différence).

CHARn'est pas binaire et l'égalité ne dépend pas uniquement de la valeur en octets mais du classement réel; dans le pire des cas Aest traité comme égal à a. Voir The _binet binaryCollations pour plus d'informations.

Gombo
la source
28
Soyez conscient - le stockage en tant que binaire (60) peut provoquer un comportement inattendu pour l'égalité des chaînes (entre autres). Dans .NET, cela peut être surmonté en utilisant String.Equals (fromDataBaseBinary60string, typiqueishString, StringComparison.InvariantCulture)
JHubbard80
8
Si vous définissez la colonne comme CHAR (60) CHARACTER SET latin1 COLLATE latin1_bin, vous bénéficiez désormais des avantages d'une comparaison précise des chaînes sans avoir besoin d'une colonne binaire.
Ben
2
@AndreFigueiredo SQL_Latin1_General_CP1_CS_ASest inconnu dans MySQL. Ce qui est connu, c'est latin1_general_cs.
Gumbo
1
J'aimerais avoir une définition ici pour ce 2, 2aet 2ymoyenne pour l' algorithme de hachage et le format. Je n'ai pas pu trouver une réponse facile avec quelques recherches.
jocull
2
@Neon Le problème est que vous pouvez comparer différents hachages pour qu'ils soient égaux. Si vous spécifiez explicitement qu'il s'agit d'une colonne binaire (ou d'un VARCHAR avec le bon classement), vous ne courez pas le risque de changer ailleurs un paramètre qui en fait une comparaison insensible à la casse. Cela rend également votre intention plus claire, ce qui est généralement une bonne chose - vous stockez des données binaires; vous devez le stocker en tant que données binaires.
Procès de Fund Monica
52

Un hachage Bcrypt peut être stocké dans une BINARY(40)colonne.

BINARY(60), comme les autres réponses le suggèrent, est le choix le plus simple et le plus naturel, mais si vous souhaitez maximiser l'efficacité du stockage, vous pouvez économiser 20 octets en déconstruisant sans perte le hachage. J'ai documenté cela plus en détail sur GitHub: https://github.com/ademarre/binary-mcf

Les hachages Bcrypt suivent une structure appelée format de cryptage modulaire (MCF). Le MCF binaire (BMCF) décode ces représentations de hachage textuelles en une structure binaire plus compacte. Dans le cas de Bcrypt, le hachage binaire résultant est de 40 octets.

Gumbo a fait un bon travail pour expliquer les quatre composants d'un hachage Bcrypt MCF:

$<id>$<cost>$<salt><digest>

Le décodage vers BMCF va comme ceci:

  1. $<id>$ peut être représenté en 3 bits.
  2. <cost>$, 04-31, peut être représenté en 5 bits. Mettez-les ensemble pour 1 octet.
  3. Le sel à 22 caractères est une représentation en base 64 (non standard) de 128 bits. Le décodage en base 64 donne 16 octets.
  4. Le condensé de hachage de 31 caractères peut être décodé en base 64 à 23 octets.
  5. Mettez tout cela ensemble pour 40 octets: 1 + 16 + 23

Vous pouvez en savoir plus sur le lien ci-dessus, ou examiner mon implémentation PHP , également sur GitHub.

Et rouge
la source
49
Coût d'un champ plus long: 20 octets fois même un million + d'enregistrements: 20 Mo, une fois que vous atteignez un million d'enregistrements +. Coût de l'implémentation incorrecte d'une longueur de champ raccourcie, dans un domaine de sécurité et d'ingénierie très complexe: $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$ Faites le calcul.
Kzqai
6
@Kzqai, comme je l'ai dit, la plus grande colonne de 60 octets est le choix le plus naturel, mais la manière agressive de poursuivre l'efficacité du stockage dépend du projet. Par exemple, il est courant d'essayer d'ajuster la base de données entière en mémoire, et 20 Mo ici et 20 autres peuvent s'additionner rapidement dans un environnement limité en mémoire.
Andre D
10
Votre exemple alimente mon propos. --- Si vous souhaitez mettre votre base de données en mémoire, optimisez toutes les autres colonnes avant de toucher la colonne de stockage bcrypt. --- Si vous avez optimisé toutes les autres colonnes à des degrés insensés, et que seule la colonne de hachage bcrypt est restée, obtenez un autre gig de mémoire juste pour bcrypt. --- Si vous avez fait les deux choses ci-dessus ... ... arrêtez, vous n'avez pas optimisé toutes les autres colonnes de fruits bas, et vous êtes sur le point de jouer avec un système de sécurité cryptographique testé qui fonctionne et de remplacer avec un système local plus compliqué avec une chance d'échec d'implémentation.
Kzqai
11
@Kzqai Il n'y a aucun risque d'affaiblir la sécurité de votre bibliothèque Bcrypt ici. Il s'agit d'un encodage de données qui est annulé lors de la récupération du stockage avant la vérification du mot de passe. Ce n'est pas un territoire "ne roulez pas votre propre crypto".
Andre D
1
Belle explication. :) Bien que votre explication ait donné une excellente idée, je veux juste aller avec 60 caractères, même 100 caractères, juste pour être sûr. Joli débat aussi @Kzqai et AndreD
Naveen Kumar V
23

Si vous utilisez PHP password_hash()avec l' PASSWORD_DEFAULTalgorithme pour générer le hachage bcrypt (qui, je suppose, est un grand pourcentage de personnes lisant cette question), assurez-vous de garder à l'esprit qu'à l'avenir password_hash(), un algorithme différent pourrait être utilisé par défaut et que cela pourrait donc affecter la longueur du hachage (mais il ne peut pas nécessairement être plus long).

Depuis la page de manuel:

Notez que cette constante est conçue pour changer au fil du temps à mesure que de nouveaux algorithmes plus puissants sont ajoutés à PHP. Pour cette raison, la longueur du résultat de l'utilisation de cet identifiant peut changer au fil du temps. Par conséquent, il est recommandé de stocker le résultat dans une colonne de base de données pouvant s'étendre au-delà de 60 caractères (255 caractères serait un bon choix).

En utilisant bcrypt, même si vous avez 1 milliard d'utilisateurs (c'est-à-dire que vous êtes actuellement en concurrence avec Facebook) pour stocker des hachages de mot de passe de 255 octets, cela ne ferait que ~ 255 Go de données - environ la taille d'un petit disque dur SSD. Il est extrêmement improbable que le stockage du hachage de mot de passe soit le goulot d'étranglement dans votre application. Cependant, dans le cas où l'espace de stockage est vraiment un problème pour une raison quelconque, vous pouvez utiliser PASSWORD_BCRYPTpour forcer password_hash()à utiliser bcrypt, même si ce n'est pas la valeur par défaut. Assurez-vous simplement de rester informé des vulnérabilités trouvées dans bcrypt et de consulter les notes de publication à chaque fois qu'une nouvelle version PHP est publiée. Si l'algorithme par défaut est modifié, il serait bon de revoir pourquoi et de prendre une décision éclairée quant à l'utilisation ou non du nouvel algorithme.

Mike
la source
20

Je ne pense pas qu'il existe des astuces intéressantes que vous pouvez faire pour stocker cela comme vous pouvez le faire par exemple avec un hachage MD5.

Je pense que votre meilleur pari est de le stocker CHAR(60)comme il est toujours de 60 caractères

James C
la source
Bien que la documentation PHP note que les colonnes devraient pouvoir contenir plus de données, pour les versions futures ...
Julian F. Weinert
16
Aucune raison de plaquer l'or. Si le logiciel que vous utilisez nécessite soixante octets, allouez-en soixante. S'il existe une version future de votre logiciel qui change cela, vous pouvez vous en inquiéter lorsque cette version se produira. Vous ne devez pas installer automatiquement des mises à jour qui modifient les fonctionnalités.
Tyler Crompton