Welchen Spaltentyp / welche Längenlänge sollte ich zum Speichern eines Bcrypt-Hash-Passworts in einer Datenbank verwenden?

317

Ich möchte ein Hash-Passwort (mit BCrypt) in einer Datenbank speichern. Was wäre ein guter Typ dafür und welche wäre die richtige Länge? Sind mit BCrypt gehashte Passwörter immer gleich lang?

BEARBEITEN

Beispiel-Hash:

$2a$10$KssILxWNR6k62B7yiX0GAe2Q7wwHlrzhF3LqtVvpyvHZf0MwvNfVu

Nach dem Hashing einiger Passwörter scheint BCrypt immer Hashes mit 60 Zeichen zu generieren.

BEARBEITEN 2

Entschuldigung, dass Sie die Implementierung nicht erwähnt haben. Ich benutze jBCrypt .

Hilfsmethode
quelle
Siehe auch Openwalls PHP Passass Hashing Framework (PHPass). Es ist tragbar und gegen eine Reihe gängiger Angriffe auf Benutzerkennwörter geschützt. Der Typ, der das Framework geschrieben hat (SolarDesigner), ist derselbe, der John The Ripper geschrieben hat und als Richter am Password Hashing-Wettbewerb teilnimmt . Er weiß also ein oder zwei Dinge über Angriffe auf Passwörter.
JWW
1
Wenn jemand auf der Suche nach einer Lösung für die Verschlüsselung darauf stößt : Gumbos Antwort gilt auch für die Verschlüsselung. Ich habe BINARY (64) persönlich in MySQL angewendet und konnte später unter Python die Byte-Gleichheit testen.
Philippe Hebert

Antworten:

367

Das modulare Krypta-Format für bcrypt besteht aus

  • $2$, $2a$ Oder $2y$Identifizieren des Hashing - Algorithmus und Format
  • ein zweistelliger Wert, der den Kostenparameter angibt, gefolgt von $
  • ein 53 Zeichen lange Basis-64-codierter Wert (sie verwenden das Alphabet ., /, 0- 9, A- Z, a- z, die die verschiedenen ist Standard Base 64 Encoding Alphabet) , bestehend aus:
    • 22 Zeichen Salz (effektiv nur 128 Bits der 132 decodierten Bits)
    • 31 Zeichen verschlüsselte Ausgabe (effektiv nur 184 Bits der 186 decodierten Bits)

Somit beträgt die Gesamtlänge 59 bzw. 60 Bytes.

Wenn Sie das 2a-Format verwenden, benötigen Sie 60 Byte. Und so für MySQL werde ich empfehlen zu verwenden CHAR(60) BINARYoderBINARY(60) (siehe Die _bin und binäre Sortierungen für Informationen über den Unterschied).

CHARist nicht binär sicher und Gleichheit hängt nicht nur vom Bytewert ab, sondern von der tatsächlichen Sortierung; im schlimmsten Fall Awird gleich behandelt a. Weitere Informationen finden Sie unter The _binund binaryCollations .

Gumbo
quelle
28
Beachten Sie, dass das Speichern als Binärdatei (60) (unter anderem) zu unerwartetem Verhalten bei der Zeichenfolgengleichheit führen kann. In .NET kann dies durch Verwendung von String.Equals (fromDataBaseBinary60string, typischishString, StringComparison.InvariantCulture)
JHubbard80
8
Wenn Sie die Spalte als CHAR (60) CHARACTER SET latin1 COLLATE latin1_bin definieren, erhalten Sie jetzt die Vorteile eines genauen Zeichenfolgenvergleichs, ohne dass eine binäre Spalte erforderlich ist.
Ben
2
@AndreFigueiredo SQL_Latin1_General_CP1_CS_ASist in MySQL unbekannt. Was bekannt ist, ist latin1_general_cs.
Gumbo
1
Ich würde gerne eine Definition haben hier für das, was 2, 2aund 2yMittel für Hashing - Algorithmus und Format. Ich konnte mit etwas Suchen keine einfache Antwort finden.
Jocull
2
@Neon Das Problem ist, dass Sie verschiedene Hashes vergleichen können, um gleich zu sein. Wenn Sie explizit angeben, dass es sich um eine Binärspalte (oder eine VARCHAR mit der richtigen Sortierung) handelt, besteht nicht das Risiko, dass Sie an einer anderen Stelle eine Einstellung ändern, bei der der Vergleich zwischen Groß- und Kleinschreibung nicht berücksichtigt wird. Es macht auch Ihre Absicht klarer, was im Allgemeinen eine gute Sache ist - Sie speichern Binärdaten; Sie sollten es als Binärdaten speichern.
Fund Monica Klage
51

Ein Bcrypt-Hash kann in einer BINARY(40)Spalte gespeichert werden .

BINARY(60)Wie die anderen Antworten vermuten lassen, ist dies die einfachste und natürlichste Wahl. Wenn Sie jedoch die Speichereffizienz maximieren möchten, können Sie 20 Byte einsparen, indem Sie den Hash verlustfrei dekonstruieren. Ich habe dies auf GitHub ausführlicher dokumentiert: https://github.com/ademarre/binary-mcf

Bcrypt-Hashes folgen einer Struktur, die als Modular Crypt Format (MCF) bezeichnet wird. Binary MCF (BMCF) decodiert diese Text-Hash-Darstellungen in eine kompaktere Binärstruktur. Im Fall von Bcrypt beträgt der resultierende binäre Hash 40 Bytes.

Gumbo hat die vier Komponenten eines Bcrypt MCF-Hashs gut erklärt:

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

Die Dekodierung in BMCF sieht folgendermaßen aus:

  1. $<id>$ kann in 3 Bits dargestellt werden.
  2. <cost>$, 04-31, kann in 5 Bits dargestellt werden. Fügen Sie diese für 1 Byte zusammen.
  3. Das 22-stellige Salt ist eine (nicht standardmäßige) Base-64-Darstellung von 128 Bit. Die Base-64-Decodierung ergibt 16 Bytes.
  4. Der 31-stellige Hash-Digest kann auf 23 Bytes decodiert werden.
  5. Setzen Sie alles für 40 Bytes zusammen: 1 + 16 + 23

Sie können mehr über den obigen Link lesen oder meine PHP-Implementierung auch auf GitHub untersuchen.

Und Rot
quelle
49
Kosten für längeres Feld: 20 Byte mal sogar eine Million + Datensätze: 20 MB, sobald Sie eine Million Datensätze + erreicht haben. Kosten für die unsachgemäße Implementierung einer verkürzten Feldlänge in einem hochkomplexen Sicherheits- und Konstruktionsbereich: $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ Sie rechnen nach.
Kzqai
6
@Kzqai, wie gesagt, die größere 60-Byte-Spalte ist die natürlichste Wahl, aber wie aggressiv die Speichereffizienz verfolgt werden soll, hängt vom Projekt ab. Beispielsweise ist es üblich, zu versuchen, die gesamte Datenbank in den Speicher einzupassen, und 20 MB hier und weitere 20 dort können sich in einer Umgebung mit eingeschränktem Speicher schnell summieren.
Andre D
10
Ihr Beispiel geht auf meinen Standpunkt ein. --- Wenn Sie Ihre Datenbank speichern möchten, optimieren Sie jede zweite Spalte, bevor Sie die bcrypt-Speicherspalte berühren. --- Wenn Sie jede zweite Spalte in einem wahnsinnigen Ausmaß optimiert haben und nur noch die bcrypt-Hash-Spalte übrig ist, holen Sie sich einen weiteren Gig Speicher nur für bcrypt. --- Wenn Sie beide oben genannten Schritte ausgeführt haben, haben Sie nicht jede zweite Spalte mit niedrig hängenden Früchten optimiert und stehen kurz davor, sich mit einem getesteten kryptografischen Sicherheitssystem zu messen, das funktioniert, und es zu ersetzen Es handelt sich um ein komplizierteres System aus eigenem Anbau mit der Möglichkeit eines Implementierungsfehlers.
Kzqai
11
@Kzqai Hier besteht kein Risiko, die Sicherheit Ihrer Bcrypt-Bibliothek zu beeinträchtigen. Es handelt sich um eine Datencodierung, die beim Abrufen aus dem Speicher vor der Kennwortprüfung rückgängig gemacht wird. Dies ist kein Gebiet, in dem Sie Ihre eigene Krypto nicht rollen.
Andre D
1
Schöne Erklärung. :) Obwohl Ihre Erklärung eine großartige Idee war, möchte ich nur mit 60 Zeichen, sogar 100 Zeichen, gehen, um auf der sicheren Seite zu sein. Schöne Debatte auch @Kzqai und AndreD
Naveen Kumar V
23

Wenn Sie PHPs password_hash()mit dem PASSWORD_DEFAULTAlgorithmus verwenden, um den bcrypt-Hash zu generieren (von dem ich annehmen würde, dass es ein großer Prozentsatz der Leute ist, die diese Frage lesen), denken Sie daran, dass dies in Zukunft der Fall istpassword_hash() möglicherweise ein anderer Algorithmus als Standard verwendet wird und dies daher möglich ist beeinflussen die Länge des Hash (aber es muss nicht unbedingt länger sein).

Aus der Handbuchseite:

Beachten Sie, dass sich diese Konstante im Laufe der Zeit ändern soll, wenn PHP neue und stärkere Algorithmen hinzugefügt werden. Aus diesem Grund kann sich die Länge des Ergebnisses aus der Verwendung dieses Bezeichners im Laufe der Zeit ändern. Daher wird empfohlen, das Ergebnis in einer Datenbankspalte zu speichern, die über 60 Zeichen hinausgehen kann (255 Zeichen wären eine gute Wahl).

Wenn Sie bcrypt verwenden, selbst wenn Sie 1 Milliarde Benutzer haben (dh Sie konkurrieren derzeit mit Facebook), um 255-Byte-Passwort-Hashes zu speichern, werden nur ~ 255 GB Daten gespeichert - ungefähr so ​​groß wie eine kleine SSD-Festplatte. Es ist äußerst unwahrscheinlich, dass das Speichern des Kennwort-Hash der Engpass in Ihrer Anwendung ist. Doch in den unwahrscheinlichen Fall, dass Speicherplatz wirklich ist ein Problem , aus irgendeinem Grunde, können Sie verwenden , PASSWORD_BCRYPTum Kraft password_hash()zu verwenden bcrypt, auch wenn das nicht der Standard. Bleiben Sie auf jeden Fall über Schwachstellen in bcrypt auf dem Laufenden und lesen Sie die Versionshinweise jedes Mal, wenn eine neue PHP-Version veröffentlicht wird. Wenn der Standardalgorithmus jemals geändert wird, sollten Sie überprüfen, warum und eine fundierte Entscheidung treffen, ob Sie den neuen Algorithmus verwenden oder nicht.

Mike
quelle
20

Ich glaube nicht, dass es nette Tricks gibt, mit denen Sie dies speichern können, wie Sie es beispielsweise mit einem MD5-Hash tun können.

Ich denke, Ihre beste Wette ist es, es als zu speichern, CHAR(60)da es immer 60 Zeichen lang ist

James C.
quelle
In der PHP-Dokumentation wird jedoch darauf hingewiesen, dass Spalten für zukünftige Versionen mehr Daten enthalten sollten ...
Julian F. Weinert
16
Kein Grund zur Goldplatte. Wenn die von Ihnen verwendete Software 60 Byte benötigt, weisen Sie 60 Byte zu. Wenn es eine zukünftige Version Ihrer Software gibt, die dies ändert, können Sie sich darüber Sorgen machen, wenn diese Version erscheint. Sie sollten Updates, die die Funktionalität ändern, nicht automatisch installieren.
Tyler Crompton