it-swarm.com.de

Warum sind gesalzene Hashes für die Kennwortspeicherung sicherer?

Ich weiß, dass es viele Diskussionen über gesalzene Hashes gibt, und ich verstehe, dass der Zweck darin besteht, es unmöglich zu machen, eine Regenbogentabelle mit allen möglichen Hashes (im Allgemeinen bis zu 7 Zeichen) zu erstellen.

Mein Verständnis ist, dass die zufälligen gesalzenen Werte einfach mit dem Passwort-Hash verknüpft werden. Warum kann eine Rainbow-Tabelle nicht für den Passwort-Hash verwendet werden und die ersten X-Bits ignorieren, von denen bekannt ist, dass sie der zufällige Salt-Hash sind?

pdate

Danke für die Antworten. Ich vermute, damit dies funktioniert, muss das Verzeichnis (LDAP usw.) ein für jeden Benutzer spezifisches Salt speichern, oder es scheint, als würde das Salt "verloren" gehen und eine Authentifizierung könnte niemals stattfinden.

250
Tsyras

Es funktioniert normalerweise so:

Angenommen, Ihr Passwort lautet "Baseball". Ich könnte es einfach roh speichern, aber jeder, der meine Datenbank erhält, erhält das Passwort. Also mache ich stattdessen einen SHA1-Hash und bekomme folgendes:

$ echo -n baseball | sha1sum
a2c901c8c6dea98958c219f6f2d038c44dc5d362

Theoretisch ist es unmöglich, einen SHA1-Hash umzukehren. Aber gehen Sie zu eine Google-Suche nach genau dieser Zeichenfolge , und Sie werden keine Probleme haben, das ursprüngliche Passwort wiederherzustellen.

Wenn zwei Benutzer in der Datenbank dasselbe Kennwort haben, haben sie denselben SHA1-Hash. Und wenn einer von ihnen ein Passwort-Hinweis hat, das try "baseball" Sagt - nun weiß ich, was beide Benutzerpasswörter sind.

Bevor wir es hashen, stellen wir eine eindeutige Zeichenfolge voran. Kein Geheimnis, nur etwas Einzigartiges. Wie wäre es mit WquZ012C. Jetzt haben wir den String WquZ012Cbaseball. Das stimmt damit überein:

c5e635ec235a51e89f6ed7d4857afe58663d54f5

Wenn Sie diesen String googeln, wird nichts angezeigt (außer vielleicht this Seite), also sind wir jetzt bei etwas. Und wenn person2 auch "Baseball" als Passwort verwendet, verwenden wir ein anderes Salz und erhalten einen anderen Hash.

Um Ihr Passwort zu testen, müssen Sie natürlich wissen, was das Salz ist. Also müssen wir das irgendwo aufbewahren. Die meisten Implementierungen setzen es einfach genau dort mit dem Hash fest, normalerweise mit einem Trennzeichen. Versuchen Sie dies, wenn Sie openssl installiert haben:

[tylerl ~]$ openssl passwd -1
Password: baseball
Verifying - Password: baseball
$1$oaagVya9$NMvf1IyubxEYvrZTRSLgk0

Dies gibt uns einen Hash unter Verwendung der Standardbibliothek crypt. Unser Hash ist also $1$oaagVya9$NMvf1IyubxEYvrZTRSLgk0: Es sind tatsächlich 3 Abschnitte, die durch $ Getrennt sind. Ich werde das Trennzeichen durch ein Leerzeichen ersetzen, um es visuell klarer zu machen:

$1$oaagVya9$NMvf1IyubxEYvrZTRSLgk0
 1 oaagVya9 NMvf1IyubxEYvrZTRSLgk0
  • 1 bedeutet "Algorithmus Nummer 1", der etwas kompliziert ist, aber MD5 verwendet. Es gibt viele andere, die viel besser sind , aber dies ist unser Beispiel.
  • oaagVya9 ist unser Salz. Genau dort hineingestürzt mit unserem Hash.
  • NMvf1IyubxEYvrZTRSLgk0 ist die tatsächliche MD5-Summe, base64-codiert.

Wenn ich den Prozess erneut ausführe, erhalte ich einen völlig anderen Hash mit einem anderen Salz. In diesem Beispiel gibt es ungefähr 1014 Möglichkeiten, dieses eine Passwort zu speichern. Alle diese sind für das Passwort "Baseball":

$1$9XsNo9.P$kTPuyvrHqsJJuCci3zLwL.
$1$nLEOCtx6$uSnz6PF8q3YuUhB3rLTC3/
$1$/jZJXTF3$OqDuk8T/cEIGpeKWfsamf.
$1$2lC.Cb/U$KR0jkhpeb1sz.UIqvfYOR.

Wenn ich jedoch absichtlich das Salz spezifiziere, das ich überprüfen möchte, erhalte ich mein erwartetes Ergebnis zurück:

[tylerl ~]$ openssl passwd -1 -salt oaagVya9
Password: baseball
Verifying - Password: baseball
$1$oaagVya9$NMvf1IyubxEYvrZTRSLgk0

Und das ist der Test, den ich durchführe, um zu überprüfen, ob das Passwort korrekt ist. Suchen Sie den gespeicherten Hash für den Benutzer, suchen Sie das gespeicherte Salt, führen Sie denselben Hash mit gespeichertem Salt erneut aus und prüfen Sie, ob das Ergebnis mit dem ursprünglichen Hash übereinstimmt.

Dies selbst implementieren

Dieser Beitrag ist kein Implementierungsleitfaden. Salzen Sie Ihren MD5 nicht einfach und nennen Sie ihn gut. Das reicht im heutigen Risikoklima nicht aus. Sie möchten stattdessen einen iterativen Prozess ausführen, der die Hash-Funktion tausende Male ausführt. Dies wurde an anderer Stelle erklärt viele Male wiederholt, daher werde ich hier nicht auf das "Warum" eingehen.

Hierfür gibt es mehrere etablierte und vertrauenswürdige Optionen:

  • crypt: Die Funktion, die ich oben verwendet habe, ist eine ältere Variante des Unix crypt Passwort-Hashing-Mechanismus. in allen Unix/Linux-Betriebssystemen. Die ursprüngliche (DES-basierte) Version ist schrecklich unsicher; denke nicht einmal darüber nach. Das, was ich gezeigt habe (MD5-basiert), ist besser, sollte aber heute noch nicht verwendet werden. Spätere Variationen, einschließlich der Variationen SHA-256 und SHA-512, sollten angemessen sein. Alle neueren Varianten implementieren mehrere Hashes.

  • bcrypt: Die Blowfish-Version des oben erwähnten Funktionsaufrufs crypt. Profitiert von der Tatsache, dass Blowfish einen sehr teuren Schlüsseleinrichtungsprozess hat und einen "Kosten" -Parameter verwendet, der die Schlüsseleinrichtungszeit entsprechend erhöht.

  • PBKDF2: ("Passwortbasierte Schlüsselableitungsfunktion Version 2") Erstellt, um aus einfachen Passwörtern starke kryptografische Schlüssel zu erzeugen ist die einzige hier aufgeführte Funktion, die tatsächlich einen RFC hat . Führt eine konfigurierbare Anzahl von Runden aus, wobei jede Runde das Passwort sowie das Ergebnis der vorherigen Runde enthält. Die erste Runde verwendet ein Salz. Es ist erwähnenswert, dass sein ursprünglicher Verwendungszweck darin besteht, starke Schlüssel zu erstellen, nicht Passwörter zu speichern, aber die Überschneidung von Zielen macht dies auch hier zu einer vertrauenswürdigen Lösung . Wenn Sie keine Bibliotheken zur Verfügung hatten und gezwungen waren, etwas von Grund auf neu zu implementieren, ist dies die einfachste und am besten dokumentierte Option. Natürlich ist es immer am besten, eine gut überprüfte Bibliothek zu verwenden.

  • scrypt: Ein kürzlich eingeführtes System, das speziell für die Implementierung auf dedizierter Hardware entwickelt wurde. scrypt hat nicht nur mehrere Runden einer Hashing-Funktion, sondern auch einen sehr großen Arbeitsspeicherstatus, um die RAM - Anforderung für Implementierungen zu erhöhen. While Sehr neu und größtenteils unbewiesen, sieht es mindestens so sicher aus wie die anderen und möglicherweise das sicherste von allen.

402
tylerl

Technisch gesehen können Sie immer noch einen Regenbogentisch verwenden, um gesalzene Hashes anzugreifen. Aber nur technisch. Ein gesalzener Hash besiegt Regenbogentabellenangriffe nicht durch Hinzufügen von Kryptomagie, sondern nur durch exponentielles Erhöhen der Größe der Regenbogentabelle, die erforderlich ist, um eine Kollision erfolgreich zu finden.

Und ja, du musst das Salz aufbewahren :)

49
xkcd

Es wird nicht nach dem Hash hinzugefügt. Es wird vor dem Hash hinzugefügt, sodass der Hash für jedes Salz völlig anders ist.

Ist es nicht

hash abcd = defg
store 123defg (for user with 123 salt) and 456defg (for user with 456 salt)  

Es ist

hash 123abcd = ghij 
hash 456abcd = klmn
23
AJ Henderson

Für Passwort-Hashes müssen Sie etwas wie PBKDF2/RFC2898/PKCS5v2 , Bcrypt oder Scrypt verwenden, mit denen Sie eine Anzahl von Iterationen ("Arbeitsfaktor") auswählen können, anstatt nur eine . PBKDF2 verwendet zum Beispiel HMAC verschlüsseltes Hashing mit einem bekannten Hash-Algorithmus (typischerweise SHA-512, SHA-256 oder SHA-1) intern für a Anzahl der Iterationen, vorzugsweise Zehntausende bis Hunderttausende, so hoch wie möglich, ohne dass sich die Benutzer beschweren.

Der Grund für die große Anzahl von Iterationen besteht darin, einen Angreifer zu verlangsamen, was wiederum den Schlüsselbereich verringert, den er in einem bestimmten Zeitraum durchlaufen kann, sodass er die besseren Passwörter nicht effektiv angreifen kann. "Passwort" und "P @ $$ w0rd" werden natürlich unabhängig von einem Offline-Angriff geknackt.

Sie haben Recht, jede Zeile (Benutzer) benötigt ihr eigenes eindeutig erzeugtes, kryptografisch zufälliges langes Salz. Dieses Salz wird im Klartext gespeichert.

Mit PBKDF2, Bcrypt oder Scrypt würde ich auch empfehlen, die Anzahl der Iterationen (Arbeitsfaktor) in der Datenbank auch im Klartext zu speichern, damit sie leicht geändert werden können (ich persönlich verwende eine etwas zufällige Anzahl von Iterationen - wenn es immer anders ist , dann gibt es weniger Angst vor "Oh nein, eine winzige Änderung könnte alles durcheinander bringen - NIEMALS WIEDER ÄNDERN" vom Management oder anderen Entwicklern.

Beachten Sie, dass Sie bei Verwendung von PBKDF2 für das Kennwort-Hashing niemals eine größere Ausgabe als die native Hash-Ausgabe anfordern müssen - für SHA-1 sind das 20 Byte und für SHA-512 64 Byte.

Um tatsächliche Beispiele für PBKDF2 mit zwei verschiedenen Salzen zu nennen:

(PBKDF2 HMAC Passwort Salt Iterationen Ausgabebytes Ergebnisse)

  • PBKDF2 HMAC-SHA-512 MyPass vA8u3v4qzCdb 131072 64
    • 2e3259bece6992f012966cbf5803103fdea7957ac20f3ec305d62994a3f4f088f26cc3889053fb59a4e3c282f55e9179695609ee1147cffae1455880993ef874
  • PBKDF2 HMAC-SHA-512 MyPass 16eZQVf7J65S 131072 64
    • 1018ad648096f7814bc2786972eb4091f6c36761a8262183c24b0f4d34abb48073ed2541ee273220915638b46ec14dfb2b23ad64c4aa12f97158340bdc12fc57
15

Zusätzlich zu dem, was Tylerl gesagt hat, ist es wichtig zu betonen, dass in der modernen Krypto Salze nicht zum Schutz vor Regenbogentischen verwendet werden. Niemand benutzt wirklich Regenbogentische. Die wirkliche Gefahr ist die Parallelisierung:

  • Wenn Sie kein Salz oder nur ein statisches Salz haben und ich Ihre DB mit einer Million Hashes stehle, kann ich alle meine Kerne darauf werfen, sie brutal zu erzwingen, und jeder Kern wird eine Million Hashes angreifen Gleichzeitig sehe ich jedes Mal, wenn ich any der als Passwörter verwendeten Zeichenfolgen drücke, eine Hash-Übereinstimmung. Also muss ich den Suchraum erschöpfen einmal um ein Millionen Passwort zu knacken. Das ist eine völlig realistische Skala von Passwortlecks und ein attraktives Ziel, um ein paar Dutzend GPUs auf oder sogar ein benutzerdefiniertes FPGA zu werfen. Selbst wenn ich nur die unteren 30% des Suchraums erschöpfe, werde ich immer noch mit 500.000 realen Passwörtern oder so davonkommen. Diese Passwörter werden dann zum Aufbau meines Wörterbuchs verwendet. Wenn also das nächste Mal jemand eine Hash-Datenbank verliert, werden 90% davon in Stunden geknackt.
  • Wenn stattdessen jedes Passwort mit einem eigenen, eindeutigen Salt gehasht wird, muss ich jedes einzelne einzeln angreifen, da selbst bei identischen Passwörtern völlig unterschiedliche Hashes gespeichert sind. Das heißt, ich könnte vielleicht meine teure, stromhungrige GPU/FPGA-Farm verwenden, um die paar hochwertigen Ziele anzugreifen (sagen wir, wenn Obama Ihr Benutzer wäre, würde das Erhalten seines Passworts immer noch die Kosten rechtfertigen), aber ich werde es nicht bekommen mehrere hunderttausend Passwörter kostenlos davon. Wenn ich die gesamten Millionen Passwörter erhalten wollte, müsste ich eine vollständige Brute-Force-Suche Millionen Mal durchführen.

Und deshalb schützt Sie jedes Salz, ob statisch oder nicht, vor vorbereiteten Regenbogentischen, solange es nicht weit verbreitet ist. Nur einzigartige Salze pro Hash schützen Sie vor der realen Gefahr, viel parallele Rechenleistung zu verwenden, um alles zu knacken auf einmal.

14
mathrick

Es ist sicherer, denn wenn mehrere Personen dasselbe Passwort haben, haben sie unterschiedliche Hashs.

Einfache Implementierung mit Python:

import hashlib

passwordA = '123456'
passwordB = '123456'

hashlib.md5(passwordA).hexdigest()
'e10adc3949ba59abbe56e057f20f883e'

hashlib.md5(passwordB).hexdigest()
'e10adc3949ba59abbe56e057f20f883e'

Und jetzt fügen wir Salz hinzu:

saltA = 'qwerty'
salbB = 'asdfgh'

passA = passwordA + saltA
passB = passwordB + saltB

hashlib.md5(passA).hexdigest()
'086e1b7e1c12ba37cd473670b3a15214'

hashlib.md5(passB).hexdigest()
'dc14768ac9876b3795cbf52c846e6847'

Dies ist eine sehr vereinfachte Version. Sie können Salz hinzufügen, wo immer Sie möchten. Am Anfang/Mitte/Ende des Passworts.

Salz ist sehr nützlich, besonders wenn Sie viele Benutzer haben, sodass jeder von ihnen unterschiedliche Hashes hat. Stellen Sie sich nun die Wahrscheinlichkeit, dieselben Passwörter zu haben für Millionen Konten wie Facebook, Google oder Twitter vor.

11
zakiakhmad

Erstens, wenn zwei Benutzer das eher schwache Passwort "Baseball" verwenden, hilft das Knacken eines Passworts überhaupt nicht, das zweite Passwort zu knacken, weil es gesalzen ist. Ohne zu salzen, haben Sie zwei Passwörter zum Preis von einem geknackt.

Zweitens enthalten Rainbow-Tabellen vorberechnete Hashes. So könnte ein Cracker den Hash von "Baseball" in einer Rainbow-Tabelle mit einer Unmenge von Einträgen nachschlagen. Viel schneller als die Berechnung der Millionen Hashes in der Rainbow-Tabelle. Und das wird durch Salzen verhindert.

Und jetzt eine wichtige: Einige Leute haben gute Passwörter, andere schlechte Passwörter. Wenn Sie eine Million Benutzer haben und drei das identische Passwort verwenden, wissen Sie nur , dass das Passwort schwach ist . Ohne zu salzen haben Sie drei identische Hashes. Wenn also jemand Ihre Datenbank mit Hashes stiehlt, kann er sofort erkennen, welche Benutzer schwache Passwörter haben, und sich darauf konzentrieren, diese zu knacken. Viel einfacher, "Baseball" zu knacken als 1keOj29fa0romn. Ohne zu salzen fallen die schwachen Passwörter auf. Beim Salzen hat der Cracker keine Ahnung, welche Passwörter schwach und welche schwer zu knacken sind.

8
gnasher729

Ob der Hash gesalzen ist oder nicht, macht nur dann einen Unterschied, wenn der Angreifer den Passwort-Hash hat. Ohne Salz kann der Hash mit einer Rainbow-Tabelle angegriffen werden: einem vorberechneten Wörterbuch, das Passwörter mit Hashes verknüpft. Ein N-Bit-Salz erhöht den Speicherbedarf für eine Rainbow-Tabelle und die Zeit für die Berechnung dieser Tabelle um den Faktor 2 ** N. So zum Beispiel mit einem 32-Bit-Salt, nur einem einzigen Eintrag im Rainbow-Tabellenwörterbuch, sagen wir für das Passwort passw0rd erfordert viele Gigabyte Speicherplatz, was eine solche Rainbow-Tabelle mit der aktuellen Speicherhardware sehr teuer macht. Wenn also ein Salz vorhanden ist, wird der Angreifer auf einen Brute-Force-Angriff auf den spezifischen Satz von Passwort-Hashes reduziert, die erhalten wurden.

Jedoch:

  • bei schwachen Passwörtern ist ein Brute-Force-Angriff in relativ kurzer Zeit erfolgreich.
  • ausreichend sichere Passwörter werden in einer Rainbow-Tabelle nicht gefunden.
  • wenn der Angreifer Zugriff auf die Hashes hat, ist die Systemsicherheit bereits gefährdet: Moderne Systeme und Protokolle enthüllen ihre Kennwort-Hashes nicht. Wenn der Angreifer keinen Zugriff auf die Kennwortdatenbank hat, können die Kennwörter auch im Klartext gespeichert werden.
  • wenn ein Angreifer das System kompromittieren muss, um zu den Hashes zu gelangen, um Kennwörter von diesen umzukehren, sind die einzigen Kennwörter, die für den Angreifer von Wert sind, diejenigen, die für andere Sicherheitsdomänen wiederverwendet werden, auf die der Angreifer noch keinen Zugriff hat. Passwörter, die nicht wiederverwendet werden, haben keinen Wert (und sicherlich weniger Wert als andere vertrauliche Informationen, die mit den Konten verknüpft sind).

Angenommen, Benutzer joewestlake verwendet das Kennwort god1234. Der Angreifer kehrt dies sofort mithilfe eines Regenbogentisches um. (Oder innerhalb weniger Minuten nach dem Knacken mit einem Brute-Force-Angriff, wenn der Hash gesalzen ist, da das Passwort so schlecht ist.) Das Problem ist nun, dass joewestlake auch god1234 für sein Google Mail-Konto und für Online-Banking, oops! Jetzt liest der Angreifer Joes E-Mails und lernt genug über Joe, damit er die Frage "Wie hieß Ihr erstes Haustier?" Leicht beantworten kann, wenn er sich bei Joes Online-Banking anmeldet.

Der Grund für Salze ist also, dass sie Benutzer etwas schützen, indem sie das Umkehren von Passwörtern mittlerer Sicherheit erschweren: Passwörter, die ohne Salz vernünftigerweise sein könnten Es wird erwartet, dass sie in einem Regenbogentisch gefunden werden, die aber stark genug sind, dass es sehr lange dauert, sie einzeln zu erzwingen. Salze bieten diesen Vorteil jedoch nur für den Fall, dass die Hashes kompromittiert werden, was bereits eine schwerwiegende Sicherheitsverletzung darstellt, und der Vorteil gilt nur für Benutzer, die ihre Kennwörter mit mittlerer Sicherheit in anderen Systemen wiederverwenden.

Angenommen, Joe hat stattdessen ein Passwort verwendet, das aus 10 zufälligen alphanumerischen Zeichen und Symbolen besteht. Dies könnte immer noch in einem Rainbow-Tisch sein, erfordert aber viel Arbeit. Selbst wenn Joe dasselbe Passwort für Google Mail und Online-Banking verwendet hat, ist er dank des Salzes sicher. Der Cracker lässt seinen Brute-Force-Crack vielleicht mehrere Stunden, vielleicht Tage lang laufen. Der Riss liefert zahlreiche schwache Passwörter von anderen Benutzern desselben Systems, die schwache Passwörter haben. Der Angreifer ist mit dieser Ausbeute zufrieden und hört auf zu knacken. Joes Passwort wird niemals rückgängig gemacht.

Wenn der Verstoß erkannt wird und Benutzern (einschließlich Joe) empfohlen wird, ihre Kennwörter zu ändern, hat Joe außerdem die Möglichkeit, den Cracking-Versuchen des Angreifers zu entkommen, selbst wenn der Angreifer weiterhin den gesamten Kennwortbereich mit mittlerer Sicherheit angreift, der Joes Kennwort enthält . Joe weiß, dass das Kennwort, das er auf dem kompromittierten System verwendet hat, genau mit seinem Google Mail- und Bankkennwort übereinstimmt. Daher versucht er, die beiden anderen zu ändern. Das Salz hilft hier, weil es den Benutzern, die ein Passwort wiederverwenden, Zeit verschafft, ihr Passwort zu ändern. Das Salz hilft nicht denen mit sehr schwachen Passwörtern, die innerhalb von Minuten geknackt werden, aber Benutzer von Passwörtern, deren Knacken Stunden oder Tage dauert, haben eine Kampfchance.

1
Kaz