it-swarm.com.de

Erleichtert es dem Angreifer, Salz zuerst zu setzen, um den Hash brutal zu erzwingen?

Viele Empfehlungen zum Speichern von Passwörtern empfehlen hash(salt + password) anstelle von hash(password + salt).

Wenn das Salz nicht zuerst gesetzt wird, kann der Angreifer das Kennwort nicht viel schneller erzwingen, da er den Status der Hashing-Funktion mit den Bytes des Salzes vorberechnen kann und dann jedes Mal, wenn er Milliarden und Billionen Versuche unternimmt, dies nur tun muss Beenden Sie die Berechnung des Hash anhand der Bytes des Passworts.

Mit anderen Worten, jede Bruteforce-Iteration muss nur den Hash des Passworts intermediateHashState(password) anstelle des gesamten hash(salt + password) berechnen.

Und wenn das Salz nach dem Passwort platziert würde, hätte der Angreifer diese Verknüpfung nicht.

Existiert dieser Vorteil und ist er von Bedeutung?

27
user123540

Für die Kennwortverwendung empfohlene Hash-Funktionen haben diesen Vorteil nicht - ich bin mir nicht sicher, ob nicht triviale Hashing-Funktionen dies tatsächlich tun, möchte dort aber keine pauschale Aussage machen.

Stattdessen mischen Hashing-Funktionen Teile aus dem gesamten Eingang in jeder Stufe. Bei der Eingabe ABCDEFGHIJKLMNOPQRSTUVWXYZ könnte der erste Schritt beispielsweise darin bestehen, das erste Zeichen mit dem letzten zu koppeln und zu iterieren, bis keine Eingabe mehr übrig ist. Dies würde AZBYCXDWEVFUGTHSIRJQKPLOMN ergeben. Angenommen, das "Salz" war ABCDEF und das Passwort war der Rest, dann ändern Sie das Passwort in PASSWORD - die Ausgabe dieses ersten Beispielschritts wäre ADBRCODWESFSPA, was nicht der Fall wäre Ich helfe dir nicht im geringsten mit dem Original-Hash.

Dies ist nur ein Beispiel - echte Hash-Funktionen arbeiten mit Binärwerten und führen für einige Unterschiede ein komplexeres Mischen durch - aber Sie können sehen, dass es keine Rolle spielt, wo sich das Salz für die Ausgabe zu einem sehr frühen Zeitpunkt ändert .

Es gibt sogar ein Prinzip ( der Lawineneffekt ), das vorschlägt, dass ein einzelnes Bit, das in der Eingabe in eine Hash-Funktion geändert wird, ungefähr 50% der Ausgabebits und die meisten Hash-Funktionen ändern sollte, sogar solche, die sind jetzt als unsicher wie MD5, folgen Sie diesem (während mein Beispiel oben nicht!).

Im Wesentlichen können Sie einen Teil eines Hashs nicht wie von Ihnen vorgeschlagen vorberechnen, es sei denn, das System weist andere Fehler auf. Wenn Sie aus irgendeinem Grund das Salz gehasht, die erste Hälfte der Ausgabe genommen und es zur Speicherung in die zweite Hälfte des Hash des Kennworts geschraubt haben, würde dies die theoretische Schwäche einführen, sodass Sie nur das berechnen müssten Hashes von Passwörtern.

14
Matthew

Eigentlich gehen Sie es umgekehrt an.

Es ist wahr, dass Sie mit hash(salt + password) das Salz vorberechnen können (siehe Hinweis unten) und nur jeden Kennwortkandidaten für alle diese Versuche hashen. Die Kosten sind die gleichen, die Sie tragen würden, wenn Sie überhaupt kein Salz verwenden würden.

Das Ziel des Salt ist jedoch nicht, das Bruteforcing eines einzelnen Hashs zu erschweren, sondern sicherzustellen, dass die Hashes für verschiedene Benutzer unterschiedlich sind, selbst wenn sie dasselbe Kennwort gewählt haben, sodass der Cracking-Aufwand nicht für mehrere Benutzer angewendet werden kann.

Nehmen wir an, Sie haben einen Paypal-Datenbank-Hashes dort abgelegt, wo MD5-Hashes verwendet wurden. Sie möchten die Passwörter 'Paypal', 'Paypal', 'Paypal123' überprüfen ...

  1. Wenn sie MD5 (Passwort) verwendet haben, können Sie jeden von ihnen trivial hashen und herausfinden, ob jemand solch ein schwaches Passwort verwendet.

  2. Wenn sie MD5 (Salt + Passwort) verwenden, können Sie das partielle MD5 (Salt) für alle vorberechnen, müssen jedoch weiterhin jeden Passwortkandidaten für jeden Benutzer hashen.

  3. Wenn sie MD5 (Passwort + Salt) verwendet haben, können Sie das partielle MD5 (Passwort) für jedes Kandidatenpasswort vorberechnen und dann ihr Salt für jeden Benutzer anwenden.

# 1 ist hier eindeutig das Schlimmste. Sie könnten zwischen # 2 und # 3 streiten, basierend auf der unterschiedlichen Länge von Passwörtern und Salzen sowie der Anzahl der Benutzer, aber ich würde # 2 als vorzuziehen betrachten. Allein aufgrund der Länge ist die erzwungene Mindestlänge für Ihre Kennwörter wahrscheinlich höher als die Salzgröße. Aber ich vermute, dass es auch beim Konstrukt Nr. 3 eine andere Schwäche geben könnte.

Ist es ein bedeutender Vorteil?

Nicht wirklich.

Erstens arbeiten viele Hash-Funktionen in Blöcken, und die Vorberechnung für Werte, die kleiner als die Blockgröße sind, speichert einfach eine Kopie der "vorberechneten Bytes". In 99% der Fälle ist die Länge von Salt und Passwort kürzer als die Blockgröße, sodass tatsächlich keine echte Vorberechnung durchgeführt wird. Sie müssten dort wirklich lange Zeichenfolgen verwenden, damit dies von Nutzen ist.

Darüber hinaus verwendet jede moderne Passwort-Hash-Funktion mindestens viele Iterationen, wenn keine fortgeschritteneren Mittel verwendet werden, um Bruteforcing teuer zu machen, und Ihre Optimierung gilt nur für die anfängliche Iteration.

In jedem Fall besteht die sicherste Möglichkeit, Salt und Passwort zu verketten, darin, ein HMAC über ihnen zu erstellen, wodurch sie in a gemischt werden besserer Weg.

33
Ángel

Viele Empfehlungen zum Speichern von Passwörtern empfehlen hash(salt + password) anstelle von hash(password + salt).

Diese Empfehlungen sind offensichtlich schlecht, da sie Ihnen sagen sollten, dass Sie eine Passwort-Hashing-Funktion verwenden sollen, die speziell für diesen Zweck entwickelt wurde, z. B. (in grober Reihenfolge von neuer und besser bis älter und schlechter):

  • Argon2 (am besten)
  • verschlüsseln
  • bcrypt (nicht schlecht, sieht aber veraltet aus)
  • PBKDF2 (alles andere als ideal, aber viel besser als Homebrew-Passwort-Hashing)

Diese Funktionen entweder:

  1. Nehmen Sie das Passwort und das Salz als separate Argumente und kümmern Sie sich daher intern um Ihre Frage.
  2. Geben Sie eine übergeordnete API an, die sich intern um die Salzgewinnung und -verwaltung kümmert:
    • Eine "Registrierungs" -Funktion, die ein Passwort akzeptiert, ein Salt generiert und eine Verifizierungszeichenfolge ausgibt, die sowohl Salt als auch Hash kapselt (z. B. password_hash() in PHP );
    • Eine "Verifizierungs" -Funktion, die ein Kennwort und eine Verifizierungszeichenfolge verwendet und überprüft, ob das Kennwort mit dem letzteren übereinstimmt (z. B. password_verify() in PHP ).

Wenn Sie Passwörter und Salze manuell verketten, machen Sie es falsch .


Das heißt, es ist im Allgemeinen besser für eine Passwort-Hashing-Funktion, zuerst das Salz und danach das Passwort zu absorbieren. Warum? Weil diese Reihenfolge generell besser ist, um Vorberechnungsangriffen zu widerstehen. In der Reihenfolge "Passwort zuerst" kann der Angreifer die Zwischenzustände vorberechnen, die allgemeinen Passwörtern entsprechen, und möglicherweise gibt es eine clevere Möglichkeit, eine große Tabelle zu erstellen, die dies ausnutzt, um ihre gesalzenen Hashes schneller zu berechnen, als dies sonst möglich wäre. Während die Salz-erste Ordnung dies unmöglich macht, gilt dies umso mehr, wenn die Salze zufällig sind.

Wenn das Salz nicht zuerst gesetzt wird, kann der Angreifer das Kennwort nicht viel schneller erzwingen, da er den Status der Hashing-Funktion mit den Bytes des Salzes vorberechnen kann und dann jedes Mal, wenn er Milliarden und Billionen Versuche unternimmt, dies nur tun muss Beenden Sie die Berechnung des Hash anhand der Bytes des Passworts.

Nein, denn der Punkt ist, dass der Angreifer die Salze nicht lernen soll, bevor er die Passwortdatenbank stiehlt. Diese von Ihnen erwähnte Vorberechnung führt nur zu einer geringfügigen Beschleunigung im Verhältnis zu den Kosten einer gut konzipierten Kennwort-Hashing-Funktion, und der vorberechnete Status eignet sich nur für den Angriff auf einen einzelnen Kennworteintrag (vorausgesetzt, es werden keine doppelten Salze verwendet, was ohnehin erforderlich ist).

Im Gegensatz dazu können sie mit der Passwort-Erstbestellung:

  • Berechnen und speichern Sie Hash-Funktionszustände für eine große Anzahl gängiger Kennwörter, bevor sie jemals die Kennwortdatenbank stehlen.
  • Verwenden Sie die vorberechneten Tabellen für Kennworteinträge, die mit unterschiedlichen Salzen gehasht wurden, auch für mehrere Kennwortdatenbanken.
25
Luis Casillas

Obwohl die obigen Antworten einige gültige Punkte aufwerfen, scheinen sie nicht ganz richtig zu sein, und es sollte beachtet werden, dass es tatsächlich Schwachstellen in bestimmten Hash-Funktionen gibt, die einen signifikanten Unterschied in den Crack-Geschwindigkeiten für "$ pass. $ Salt" bewirken. oder "$ salt. $ pass".

Siehe zum Beispiel md5. Laut atom ( https://hashcat.net/forum/thread-8365.html ), dem Ersteller der Hashcat-Software zum Knacken von Passwörtern:

Die Art und Weise, wie Hashcat einige Schwachstellen in MD5 ausnutzt, um zusätzliche Beschleunigung zu erhalten, erfordert, dass nur die ersten 4 Bytes der Eingabedaten geändert werden. Da dieser Teil (wegen des Salzes) fest ist, kann er die Beschleunigung nicht verwenden.

Das spiegelt sich deutlich in der Rissgeschwindigkeit wider.
Auf einem Titan RTX ist die Geschwindigkeit für md5 ($ pass. $ Salt) mit 63819,9 MH/s fast doppelt so hoch wie für md5 ($ salt. $ Pass) mit "nur" 34696,2 MH/s.

Ähnliche Unterschiede bestehen für andere Hash-Algorithmen. Die Entwickler und die Community der Software zum Knacken von Passwörtern verbringen viel Zeit damit, Schwachstellen und Verknüpfungen zu finden, um die Geschwindigkeit zu verbessern. Aus einer knackigen Perspektive kann es daher eine gute Idee sein, aktuelle Hashcat-Benchmarks wie diesen zu betrachten https://Gist.github.com/Chick3nman/5d261c5798cf4f3867fe7035ef6dd49f und die Geschwindigkeiten für die verschiedenen Salt-Passwörter zu vergleichen -Varianten.
Wenn dieser Link fehlt, können Sie mit dem folgenden Befehl auch einen eigenen Benchmark erstellen:

hashcat -b
1
Denis