it-swarm.com.de

HMAC - Warum nicht HMAC zur Passwortspeicherung?

Nota bene: Mir ist bewusst, dass die gute Antwort zum Sichern des Passwortspeichers entweder scrypt ist oder bcrypt . Diese Frage dient nicht der Implementierung in die eigentliche Software, sondern meinem eigenen Verständnis.

Angenommen, Joe Programmer hat die Aufgabe, Endbenutzerkennwörter sicher in einer Datenbank für eine Webanwendung zu speichern. oder Speichern von Passwörtern auf der Festplatte für die Anmeldung an einer Software. Er wird höchstwahrscheinlich:

  1. Beziehen Sie $password Vom Endbenutzer.
  2. Erstellen Sie $nonce Als zufälligen Wert mit einer Größe von 64 oder 128 Bit.
  3. Erstellen Sie $hash = SHA256($nonce$password) und speichern Sie $nonce Zusammen mit $hash In der Datenbank.

Frage eins:

Warum ist das Folgende nicht wesentlich besser als das Obige?

  1. Erstellen Sie $long_string Einmal und nur einmal. Speichern Sie dies als Konstante im Anwendungscode. $long_string Könnte f.x. 2 Kilobyte zufälliger Zeichen sein.
  2. Beziehen Sie $password Vom Endbenutzer.
  3. Erstellen Sie $mac = HMAC-SHA256($long_string)[$password] (d. H. Erstellen Sie einen MAC mit dem Endbenutzerkennwort als Schlüssel) und speichern Sie diesen $mac In der Datenbank.

Ich würde mir vorstellen, dass der HMAC die folgenden Vorteile hat?

  • Kollisionen sind seltener?
  • Es ist rechnerisch etwas teurer als einfaches Hashing? (Aber natürlich nicht annähernd verschlüsselt.)
  • Um mit einem Brute-Force-Angriff innerhalb einer angemessenen Zeit erfolgreich zu sein, müsste der Angreifer Zugriff auf zwei Dinge erhalten: 1) die Datenbank, in der $mac Gespeichert ist, und 2) der Anwendungscode, in dem das Original $long_string gespeichert ist. Das ist eine bessere als eine Hash-Funktion, bei der der Angreifer nur Zugriff auf die Datenbank benötigt?

Aber dennoch scheint niemand die Verwendung eines HMAC vorzuschlagen, also muss ich etwas falsch verstehen?

Frage zwei:

Welche Auswirkungen hätte das Hinzufügen eines Salzwerts $nonce?

  1. Erstellen Sie $long_string Einmal und nur einmal. Speichern Sie dies als Konstante im Anwendungscode.
  2. Beziehen Sie $password Vom Endbenutzer.
  3. Erstellen Sie $nonce Als zufälligen Wert mit einer Größe von ca. 128 Bit.
  4. Erstellen Sie $mac = HMAC-SHA256($long_string)[$nonce$password] und speichern Sie $nonce Und $mac In der Datenbank.
46
Jesper M

Der springende Punkt ist, die Aufteilung der Angriffskosten zu verhindern: Wenn ein Angreifer zwei Passwörter angreifen möchte, sollte dies doppelt so teuer sein wie der Angriff auf ein Passwort.

Mit Ihrem Vorschlag (Ihrer "Frage 1") verwenden zwei Benutzer mit demselben Kennwort denselben MAC. Wenn ein Angreifer Lesezugriff auf Ihre Datenbank hat, kann er Kennwörter "versuchen" (indem er den MAC neu berechnet) und die Datenbank nach Übereinstimmungen durchsuchen. Er kann dann alle die Passwörter parallel angreifen, um die Kosten für einen Angriff zu tragen. Wenn dein long_string ist eine fest codierte Konstante im Anwendungsquellcode, dann teilen sich alle installierten Instanzen der Anwendung diese Konstante, und es lohnt sich (für den Angreifer), ein großes Wörterbuch von Kennwort-zu-MAC-Paaren vorab zu berechnen, das auch als "a" bezeichnet wird Regenbogentisch ".

Mit einer Nonce (Ihrer "Frage 2") vermeiden Sie die Kostenteilung. Das Nonce ist normalerweise als "Salz" bekannt. Ihre long_string und die Verwendung von HMAC bringt Ihnen hier nicht viel (und Sie verwenden HMAC übrigens nicht für das, wofür es entwickelt wurde, also befinden Sie sich kryptografisch gesehen auf wackeligen Fundamenten). Die Verwendung eines Salzes ist eine sehr gute Idee (na ja, nicht die Verwendung eines Salzes ist zumindest eine sehr schlechte Idee), aber es macht nur die Hälfte der Arbeit. Sie müssen auch eine langsame Hashing-Prozedur haben. Der Punkt hier ist, dass das Salz die Kostenteilung verhindert, aber nicht den Angriff auf ein einzelnes Passwort verhindert. Ein Passwort anzugreifen bedeutet, mögliche Passwörter zu versuchen, bis eines übereinstimmt (das ist der "Wörterbuchangriff"), und angesichts der Vorstellungskraft eines durchschnittlichen menschlichen Benutzers funktionieren Wörterbuchangriffe in der Regel: Menschen verwenden einfach Liebe Passwörter, die dies können erraten werden. Die Problemumgehung besteht darin, einen Hashing-Prozess zu verwenden, der von Natur aus langsam ist, normalerweise indem die Hash-Funktion einige tausend Mal wiederholt wird. Die Idee ist, die Kennwortüberprüfung teurer zu machen: Es ist keine Schwierigkeit, den Benutzer 1 ms statt 1 µs warten zu lassen (der Benutzer wird es nicht bemerken), aber es wird auch den Wörterbuchangriff 1000-mal teurer machen. Ihre long_stringdarf dafür verwendet werden, vorausgesetzt es ist wirklich lang (nicht 2 Kilobyte, sondern 20 Megabyte).

HMAC kann anstelle einer Raw-Hash-Funktion verwendet werden, um ein Passwortüberprüfungssystem zu stärken, jedoch in einem anderen Setup. Bei einem System, das Passwörter mit Salzen und iterierten Hash-Funktionen überprüft, können Sie die Hash-Funktion durch HMAC ersetzen, indem Sie einen geheimen Schlüssel verwenden K . Dies verhindert Offline-Wörterbuchangriffe, solange Sie K geheim halten können. Einen Wert geheim zu halten ist nicht einfach, aber es ist immer noch einfacher, ein 128-Bit K geheim zu halten als eine vollständige Datenbank.

35
Thomas Pornin

HMAC kauft Ihnen hier nicht viel, obwohl ich denke, dass es als austauschbare Hash-Funktion fungiert (austauschbar durch Ändern des Schlüssels). Jedenfalls scheint es hier einfach übertrieben zu sein.

Das erste Schema, das Sie oben vorschlagen, schlägt jedoch katastrophal fehl, wenn $ long_string einem Angreifer bekannt wird. Dies ist wahrscheinlich der Fall, da der Code wahrscheinlich nicht als geheim angesehen wird (und es im Allgemeinen eine schlechte Praxis ist, sich auf die Geheimhaltung des Codes zu verlassen).

Sie sollten das zweite Schema verwenden, da $ nonce zum Schutz vor vorberechneten Angriffen erforderlich ist.

3
frankodwyer