it-swarm-eu.dev

Empfohlene Anzahl von Runden für bcrypt

Was ist heutzutage (Juli 2012) die empfohlene Anzahl von bcrypt-Runden zum Hashing eines Passworts für eine durchschnittliche Website (nur Name, E-Mail-Adresse und Privatadresse, aber keine Kreditkarte oder medizinische Informationen)?

Mit anderen Worten, was ist die aktuelle Fähigkeit der bcrypt-Community zum Knacken von Passwörtern? Mehrere bcrypt-Bibliotheken verwenden standardmäßig 12 Runden (2 ^ 12 Iterationen). Ist das der empfohlene Arbeitsfaktor? Wären 6 Runden nicht stark genug (was zufällig die Grenze für clientseitiges bcrypt-Hashing in Javascript darstellt, siehe auch Herausfordernde Herausforderung: clientseitiges Passwort-Hashing und serverseitige Passwortüberprüfung )?

Ich habe die Antwort https://security.stackexchange.com/a/3993/11197 gelesen, die eine eingehende Diskussion darüber gibt, wie die verschiedenen Faktoren ausgeglichen werden können (allerdings für PBKDF2-SHA256). Ich suche jedoch eine tatsächliche Nummer. Eine Faustregel.

94
Jason Smith

Ich denke, die Antwort auf alle Ihre Fragen ist bereits in Thomas Pornins Antwort enthalten. Sie haben darauf verlinkt, also wissen Sie vermutlich davon, aber ich schlage vor, dass Sie es erneut lesen.

Die Grundprinzipien sind: Wähle keine Anzahl von Runden; Wählen Sie stattdessen die Zeit, die die Kennwortüberprüfung auf Ihrem Server benötigt, und berechnen Sie dann die Anzahl der Runden basierend darauf. Sie möchten, dass die Überprüfung so lange dauert, wie Sie stehen können.

Einige Beispiele für konkrete Zahlen finden Sie in der Antwort von Thomas Pornin. Er schlägt vor, dass ein vernünftiges Ziel darin besteht, dass die Kennwortüberprüfung/das Hashing 241 Millisekunden pro Kennwort dauert. (Hinweis: Thomas hat anfangs "8 Millisekunden" geschrieben, was falsch ist - dies ist die Zahl für eine Geduld von einem Tag anstelle eines Monats.) Auf diese Weise kann Ihr Server immer noch 4 Kennwörter pro Sekunde überprüfen (mehr, wenn Sie dies parallel tun können). Thomas schätzt, dass, wenn dies Ihr Ziel ist, ungefähr 20.000 Runden im richtigen Stadion liegen.

Die optimale Anzahl von Runden ändert sich jedoch mit Ihrem Prozessor. Im Idealfall messen Sie, wie lange Ihr Prozessor benötigt, und wählen die Nummer entsprechend aus. Das dauert nicht so lange; Um optimale Ergebnisse zu erzielen, erstellen Sie einfach das Skript und ermitteln Sie, wie viele Runden erforderlich sind, um sicherzustellen, dass das Hashing von Kennwörtern auf Ihrem Server etwa 240 Millisekunden dauert (oder länger, wenn Sie es ertragen können).

41
D.W.

Bei der Erstveröffentlichung von BCrypt im Jahr 1999 wurden die Standardkostenfaktoren ihrer Implementierung aufgeführt:

  • normaler Benutzer: 6
  • superuser: 8

Sie bemerken auch:

Natürlich sollten die Kosten, die die Menschen wählen, von Zeit zu Zeit neu bewertet werden

Ein Verschlüsselungspreis von 6 bedeutet 64 Runden (2 6  = 64).

Wenn wir diesen anfänglichen Wert "normaler Benutzer" Verwenden, möchten wir versuchen, die Inflation der Rechenleistung anzupassen ( vorausgesetzt, sie verdoppelt sich im Durchschnitt alle 18 Monate ).

R = R. × 2(Monate/18)
R = 64 × 2(Monate/18)

Heute (9. März 2015) sind 171 Monate seit dem 31.12.1999 vergangen (oder verwenden Sie der Einfachheit halber den 1.1.2000). Die Anzahl der Runden hätte sich etwas mehr als neunmal verdoppeln müssen:

R = 64 × 2(171/18)
R = 64 × 29.5
R = 64 × 724,1
R = 46.341,0

Am Ende wollen wir das wieder in einen Kostenfaktor Konvertieren

kosten = ln (R)/ln (2)
Kosten = ln (46.341,0)/ln (2)
Kosten = 15,5

Die Praktikabilität eines Kostenfaktors von 15 hängt von der Rechenleistung Ihres Servers ab. Mein Desktop-PC ist beispielsweise eine Intel Core i7-2700K-CPU mit 3,50 GHz. Ich habe ursprünglich eine BCrypt-Implementierung am 23.01.2014 bewertet:

1/23/2014  Intel Core i7-2700K CPU @ 3.50 GHz

| Cost | Iterations        |    Duration |
|------|-------------------|-------------|
|  8   |    256 iterations |     38.2 ms | <-- minimum allowed by BCrypt
|  9   |    512 iterations |     74.8 ms |
| 10   |  1,024 iterations |    152.4 ms | <-- current default (BCRYPT_COST=10)
| 11   |  2,048 iterations |    296.6 ms |
| 12   |  4,096 iterations |    594.3 ms |
| 13   |  8,192 iterations |  1,169.5 ms |
| 14   | 16,384 iterations |  2,338.8 ms |
| 15   | 32,768 iterations |  4,656.0 ms |
| 16   | 65,536 iterations |  9,302.2 ms |

Aber das war 2014

Diese Zeitpunkte wurden ursprünglich zu Beginn des Jahres 2014 berechnet. Für meine Berechnung sollten nur 156 Monate (statt 171) Monate verwendet werden:

R = 64 × 2(156/18)
R = 64 × 28.66
R = 64 × 406,8
R = 26.035,2

kosten = ln (R)/ln (2)
Kosten = ln (26.035,2)/ln (2)
Kosten = 14,7

Der i7-2700K wurde jedoch bereits eingestellt

Der i7-2700K wurde bereits eingestellt (1. Quartal 2013), als ich meine Benchmarks durchführte. Es wurde im vierten Quartal 2011 veröffentlicht und war auf dem neuesten Stand der Technik. Wenn ich die Zahlen für das vierte Quartal 2011 verwende:

R = 64 × 2(129/18)
R = 64 × 27.16
R = 64 × 143,7
R = 9.196,8

kosten = ln (R)/ln (2)
Kosten = ln (9.196,8)/ln (2)
Kosten = 13,2

Ein Preis von 13 ist auf meinem Desktop, fast 2 Sekunden über eine Sekunde.

Wie lange kannst du es aushalten?

Das gibt Ihnen einen Eindruck von den Verzögerungen, die die ursprünglichen Implementierer beim Schreiben in Betracht gezogen haben: ~ 0,5-1 Sekunden.

Aber je länger Sie stehen können, desto besser. Jede BCrypt-Implementierung, die ich gesehen habe, verwendet 10 als Standardkosten. Und meine Implementierung hat das benutzt. Ich glaube, es ist Zeit für mich, die Standardkosten auf 12 zu erhöhen.

Zukunftssicherheit

Ich könnte auch die Hash-Funktion ändern:

hash = HashPassword("correct battery horse stapler");

d.h. derjenige, bei dem Sie sich auf die Standardkosten verlassen, um stattdessen automatisch gleitende Kosten zu verwenden. Auf diese Weise steigen die Kosten mit der Zeit von selbst. Ändern:

String HashPassword(String password)
{
   return BCrypt.HashPassword(password, BCRYPT_DEFAULT_COST);
}

zu so etwas wie:

String HashPassword(String password)
{  
   /*
     Rather than using a fixed default cost, run a micro-benchmark
     to figure out how fast the CPU is.
     Use that to make sure that it takes **at least** 250ms to calculate
     the hash
   */
   Int32 costFactor = this.CalculateIdealCost();
   //Never use a cost lower than the default hard-coded cost
   if (costFactor < BCRYPT_DEFAULT_COST) 
      costFactor = BCRYPT_DEFAULT_COST;

   return BCrypt.HashPassword(password, costFactor);
}

Int32 CalculateIdealCost()
{
    //Benchmark using a cost of 5 (the second-lowest allowed)
    Int32 cost = 5;

    var sw = new Stopwatch();
    sw.Start();
    this.HashPassword("microbenchmark", cost);
    sw.Stop();

    Double durationMS = sw.Elapsed.TotalMilliseconds;

    //Increasing cost by 1 would double the run time.
    //Keep increasing cost until the estimated duration is over 250 ms
    while (durationMS < 250)
    {
       cost += 1;
       durationMS *= 2;
    }

    return cost;
}

Bearbeiten 12.03.2015 : Aktualisierte Geschwindigkeitsnummern. Der Delphi XE6 32-Bit-Compiler (c.2013) generiert Code um eine Größenordnung schneller als Delphi 5 (c.1999) für denselben Prozessor. Der Delphi XE6 64-Bit-Compiler generiert Code 20% langsamer als der 32-Bit-Compiler.

61
Ian Boyd

Stärkere Tastenableitung über sequentielle speicherharte Funktionen ist ein sehr gutes Papier zum Thema Tastendehnung. Auf Seite 14 werden verschiedene Hashing-Algorithmen damit verglichen, wie viel Geld es kosten wird, den Hash zu brechen. Dies ist eine nützliche Methode, um über diese Dinge nachzudenken. (Nebenbei bemerkt, ChromeOS verwendet Scrypt, wenn TPM nicht verfügbar ist.)

Die Idee ist, dass diese Passwort-Hashes so lange wie möglich nicht unterbrochen werden sollen. Nach Moores Gesetz ist dies ein exponentiell schnelles Ziel. Scrypt verwendet eine variable Menge an Speicher und CPU. Diese Variable kann in Abhängigkeit von der Zeit schwerer werden. Jedes Mal, wenn sich der Client anmeldet, können Sie den Kennwort-Hash aktualisieren, um die Sicherheit zu erhöhen. Im Fall von PBKDF2 könnte dies wie rounds=2^(current_year-2000) oder so ähnlich aussehen.

Es ist wichtig zu beachten, dass Sie diese Verarbeitung nicht einfach auf den Client auslagern können und erwarten, dass Ihr Protokoll sicher ist. Bei allen mir bekannten clientseitigen Hashing-Authentifizierungsprotokollen muss der Server eine identische Berechnung durchführen, um die Authentifizierungsdaten (NTLM, NTLMv2, SRP, WPA-PSK ...) zu überprüfen.

3
rook