Best Practices: Passwörter salzen und pfeffern?


145

Ich stieß auf eine Diskussion, in der ich erfuhr, dass das, was ich getan hatte, nicht darin bestand, Passwörter zu salzen, sondern sie zu peppen, und seitdem habe ich begonnen, beides mit einer Funktion wie:

hash_function($salt.hash_function($pepper.$password)) [multiple iterations]

Ignoriert man den gewählten Hash-Algorithmus (ich möchte, dass dies eine Diskussion über Salze und Paprika ist und nicht über bestimmte Algorithmen, aber ich verwende einen sicheren), ist dies eine sichere Option oder sollte ich etwas anderes tun? Für diejenigen, die mit den Begriffen nicht vertraut sind:

  • Ein Salt ist ein zufällig generierter Wert, der normalerweise mit der Zeichenfolge in der Datenbank gespeichert wird, um die Verwendung von Hash-Tabellen zum Knacken von Kennwörtern zu verhindern. Da jedes Passwort sein eigenes Salz hat, müssen sie alle einzeln brutal gezwungen werden, um sie zu knacken. Da das Salt jedoch mit dem Kennwort-Hash in der Datenbank gespeichert ist, bedeutet ein Datenbankkompromiss, dass beide verloren gehen.

  • Ein Pfeffer ist ein standortweiter statischer Wert, der getrennt von der Datenbank gespeichert wird (normalerweise im Quellcode der Anwendung fest codiert) und der geheim sein soll. Es wird verwendet, damit ein Kompromiss der Datenbank nicht dazu führt, dass die Kennworttabelle der gesamten Anwendung brutal erzwungen wird.

Fehlt mir etwas und ist das Salzen und Peppen meiner Passwörter die beste Option, um die Sicherheit meiner Benutzer zu schützen? Gibt es eine potenzielle Sicherheitslücke auf diese Weise?

Hinweis: Nehmen Sie zum Zweck der Diskussion an, dass die Anwendung und die Datenbank auf separaten Computern gespeichert sind, keine Kennwörter usw. freigeben, sodass ein Verstoß gegen den Datenbankserver nicht automatisch einen Verstoß gegen den Anwendungsserver bedeutet.


3
Nicht ganz ein Duplikat, aber extrem verwandt: stackoverflow.com/questions/16594613/…
ircmaxell

Antworten:


306

OK. Da ich zu schreiben über diese müssen über und über allein, ich werde auf Pfeffer eine letzte kanonische Antwort tun.

Der scheinbare Vorteil von Paprika

Es scheint ziemlich offensichtlich, dass Paprika Hash-Funktionen sicherer machen sollte. Ich meine, wenn der Angreifer nur Ihre Datenbank erhält, sollten die Kennwörter Ihrer Benutzer sicher sein, oder? Scheint logisch, oder?

Deshalb glauben so viele Leute, dass Paprika eine gute Idee ist. Es ergibt Sinn".

Die Realität der Paprika

In den Bereichen Sicherheit und Kryptografie reicht "Sinn machen" nicht aus. Etwas muss beweisbar und sinnvoll sein, damit es als sicher gilt. Darüber hinaus muss es wartbar implementiert werden können. Das sicherste System, das nicht gewartet werden kann, gilt als unsicher (denn wenn ein Teil dieser Sicherheit ausfällt, fällt das gesamte System auseinander).

Und Paprika passt weder zu den nachweisbaren noch zu den wartbaren Modellen ...

Theoretische Probleme mit Paprika

Nachdem wir die Bühne bereitet haben, schauen wir uns an, was mit Paprika nicht stimmt.

  • Das Einspeisen eines Hash in einen anderen kann gefährlich sein.

    In Ihrem Beispiel tun Sie das hash_function($salt . hash_function($pepper . $password)).

    Wir wissen aus früheren Erfahrungen, dass das "Einspeisen" eines Hash-Ergebnisses in eine andere Hash-Funktion die Gesamtsicherheit verringern kann. Der Grund ist, dass beide Hash-Funktionen zum Angriffsziel werden können.

    Aus diesem Grund verwenden Algorithmen wie PBKDF2 spezielle Operationen, um sie zu kombinieren (in diesem Fall hmac).

    Der Punkt ist, dass es zwar keine große Sache ist, es aber auch keine triviale Sache ist, einfach herumzuwerfen. Kryptosysteme wurden entwickelt, um Fälle zu vermeiden, die funktionieren sollten, und konzentrieren sich stattdessen auf Fälle, die funktionieren sollen.

    Dies mag zwar rein theoretisch erscheinen, ist es aber tatsächlich nicht. Beispielsweise kann Bcrypt keine beliebigen Passwörter akzeptieren . Das Übergeben bcrypt(hash(pw), salt)kann also in der Tat zu einem weitaus schwächeren Hash führen, als bcrypt(pw, salt)wenn hash()eine binäre Zeichenfolge zurückgegeben wird.

  • Gegen Design arbeiten

    Die Art und Weise, wie bcrypt (und andere Passwort-Hashing-Algorithmen) entwickelt wurden, besteht darin, mit einem Salz zu arbeiten. Das Konzept eines Pfeffers wurde nie eingeführt. Dies mag wie eine Trivialität erscheinen, ist es aber nicht. Der Grund ist, dass ein Salz kein Geheimnis ist. Es ist nur ein Wert, der einem Angreifer bekannt sein kann. Ein Pfeffer hingegen ist per Definition ein kryptografisches Geheimnis.

    Die aktuellen Passwort-Hashing-Algorithmen (bcrypt, pbkdf2 usw.) sind alle so konzipiert, dass sie nur einen geheimen Wert (das Passwort) annehmen. Das Hinzufügen eines weiteren Geheimnisses zum Algorithmus wurde überhaupt nicht untersucht.

    Das heißt nicht, dass es nicht sicher ist. Das heißt, wir wissen nicht, ob es sicher ist. Und die allgemeine Empfehlung für Sicherheit und Kryptografie lautet: Wenn wir es nicht wissen, ist dies nicht der Fall.

    Bis Algorithmen von Kryptographen für die Verwendung mit geheimen Werten (Peppers) entworfen und überprüft werden, sollten aktuelle Algorithmen nicht mit ihnen verwendet werden.

  • Komplexität ist der Feind der Sicherheit

    Ob Sie es glauben oder nicht, Komplexität ist der Feind der Sicherheit . Das Erstellen eines Algorithmus, der komplex aussieht, kann sicher sein oder auch nicht. Aber die Chancen stehen sehr gut, dass es nicht sicher ist.

Wesentliche Probleme mit Paprika

  • Es ist nicht wartbar

    Ihre Implementierung von Paprika schließt die Möglichkeit aus, die Pfeffertaste zu drehen. Da der Pfeffer am Eingang der Einwegfunktion verwendet wird, können Sie den Pfeffer während der gesamten Lebensdauer des Werts niemals ändern. Dies bedeutet, dass Sie sich einige Wonky-Hacks einfallen lassen müssen, um die Schlüsselrotation zu unterstützen.

    Dies ist äußerst wichtig, da es immer dann erforderlich ist, wenn Sie kryptografische Geheimnisse speichern. Das Fehlen eines Mechanismus zum Drehen von Schlüsseln (regelmäßig und nach einem Verstoß) ist eine große Sicherheitslücke.

    Und Ihr aktueller Pfefferansatz würde erfordern, dass jeder Benutzer entweder sein Passwort durch eine Rotation vollständig ungültig macht oder wartet, bis sein nächstes Login rotiert (was möglicherweise nie der Fall ist) ...

    Das macht Ihren Ansatz im Grunde zu einem sofortigen No-Go.

  • Sie müssen Ihre eigene Krypto rollen

    Da kein aktueller Algorithmus das Konzept eines Pfeffers unterstützt, müssen Sie entweder Algorithmen erstellen oder neue erfinden, um einen Pfeffer zu unterstützen. Und wenn Sie nicht sofort erkennen können, warum das eine wirklich schlechte Sache ist:

    Jeder, vom ahnungslosesten Amateur bis zum besten Kryptographen, kann einen Algorithmus erstellen, den er selbst nicht brechen kann.

    Rollen Sie NIEMALS Ihre eigene Krypto ...

Der bessere Weg

Von allen oben beschriebenen Problemen gibt es zwei Möglichkeiten, mit der Situation umzugehen.

  • Verwenden Sie einfach die vorhandenen Algorithmen

    Wenn Sie bcrypt oder scrypt korrekt verwenden (mit hohen Kosten), sollten alle bis auf die schwächsten Wörterbuchkennwörter statistisch sicher sein. Der aktuelle Rekord für das Hashing von bcrypt zu Kosten von 5 liegt bei 71.000 Hashes pro Sekunde. Bei dieser Rate würde es Jahre dauern, bis ein zufälliges Passwort mit 6 Zeichen geknackt ist. Wenn man bedenkt, dass meine empfohlenen Mindestkosten 10 betragen, werden die Hashes pro Sekunde um den Faktor 32 reduziert. Wir würden also nur über 2200 Hashes pro Sekunde sprechen. Bei dieser Rate können sogar einige Wörterbuchphrasen oder Änderungen sicher sein.

    Außerdem sollten wir an der Tür nach diesen schwachen Klassen von Passwörtern suchen und sie nicht zulassen. Wenn das Knacken von Passwörtern weiter fortgeschritten ist, sollten auch die Anforderungen an die Passwortqualität steigen. Es ist immer noch ein statistisches Spiel, aber mit einer geeigneten Speichertechnik und sicheren Passwörtern sollte jeder praktisch sehr sicher sein ...

  • Verschlüsseln Sie den Ausgabe-Hash vor der Speicherung

    Im Sicherheitsbereich gibt es einen Algorithmus, der für alles ausgelegt ist, was wir oben gesagt haben. Es ist eine Blockchiffre. Es ist gut, weil es reversibel ist, so dass wir die Schlüssel drehen können (yay! Wartbarkeit!). Es ist gut, weil es wie geplant verwendet wird. Es ist gut, weil es dem Benutzer keine Informationen gibt.

    Schauen wir uns diese Zeile noch einmal an. Angenommen, ein Angreifer kennt Ihren Algorithmus (der für die Sicherheit erforderlich ist, andernfalls für die Sicherheit durch Dunkelheit). Mit einem traditionellen Pfefferansatz kann der Angreifer ein Sentinel-Passwort erstellen, und da er das Salz und die Ausgabe kennt, kann er den Pfeffer brutal erzwingen. Ok, das ist ein langer Weg, aber es ist möglich. Mit einer Chiffre bekommt der Angreifer nichts. Und da das Salz zufällig ausgewählt wurde, hilft ihm ein Sentinel-Passwort nicht einmal. Das Beste, was ihnen bleibt, ist, das verschlüsselte Formular anzugreifen. Dies bedeutet, dass sie zuerst Ihren verschlüsselten Hash angreifen müssen, um den Verschlüsselungsschlüssel wiederherzustellen, und dann die Hashes angreifen müssen. Aber es gibt eine Menge Forschung zum Angriff auf Chiffren, deshalb wollen wir uns darauf verlassen.

TL / DR

Verwenden Sie keine Paprika. Es gibt eine Vielzahl von Problemen mit ihnen, und es gibt zwei bessere Möglichkeiten: kein serverseitiges Geheimnis zu verwenden (ja, es ist in Ordnung) und den Ausgabe-Hash vor dem Speichern mit einer Blockverschlüsselung zu verschlüsseln.


6
Vielen Dank, dass Sie den letzten Teil der Verschlüsselung des Hash-Werts aufgenommen haben. Dies ist eine Antwort, der ich voll und ganz zustimmen kann. Wenn die Verschlüsselung Teil Ihrer Passwort-API werden würde, gäbe es keinen Grund, sie nicht zu verwenden, also vielleicht ... (ich würde gerne die Dokumentation dafür schreiben)
martinstoeckli

2
@martinstoeckli: Ich würde nicht zustimmen, den Verschlüsselungsschritt zur vereinfachten Hashing-API hinzuzufügen. Der Grund dafür ist, dass die Aufbewahrung von Geheimnissen (Schlüsseln) viel schwieriger ist, als die Leute glauben, und es ziemlich einfach ist, sich in den Fuß zu schießen. Für 99,9% der Benutzer da draußen ist rohes bcrypt mehr als ausreichend für alle außer den einfachsten Passwörtern ...
ircmaxell

7
@ircmaxell - Auf der anderen Seite würden Sie nichts verlieren. Im schlimmsten Fall, wenn der Schlüssel bekannt wird, muss ein Angreifer den BCrypt-Hash immer noch knacken (dieselbe Situation wie ohne Verschlüsselung). Dies ist nicht dasselbe wie das Speichern eines Schlüssels zum Verschlüsseln von Daten. Hier geht es darum, ein serverseitiges Geheimnis hinzuzufügen. Selbst ein fest codierter Schlüssel würde diese schwachen Passwörter schützen, solange der Angreifer keine Kontrolle über den Server / Code hat. Diese Situation ist nicht ungewöhnlich: Abgesehen von der SQL-Injection können auch weggeworfene Backups, verworfene Server… zu dieser Situation führen. Viele PHP-Benutzer arbeiten auf gehosteten Servern.
Martinstoeckli

2
@martinstoeckli Ich müsste hier ircmaxwell zustimmen, ich glaube nicht, dass Verschlüsselung in die Passwort-API gehört. Es kann jedoch beachtet werden, dass für maximale Sicherheit die Verschlüsselung Ihrer Hashes eine zusätzliche Bestimmung ist, die verwendet werden kann.
Foochow

Ich habe eine Frage zur Verschlüsselung der Ausgabe vor der Speicherung. Wenn ich mich nicht irre, werden Verschlüsselungsschlüssel im Allgemeinen verwendet, um Nachrichten eindeutig oder vorübergehend zu verschlüsseln. Wenn Sie jedoch 200.000 Benutzerkennwörter haben, die alle mit demselben Schlüssel verschlüsselt und zusammen gespeichert sind, ist es dann nicht einfacher, den Schlüssel anzugreifen? Sie haben jetzt 200.000 Nachrichten, verglichen mit nur 1 oder 2.
AgmLauncher

24

Zunächst sollten wir über den genauen Vorteil eines Pfeffers sprechen :

  • Der Pfeffer kann schwache Passwörter vor einem Wörterbuchangriff schützen, in dem speziellen Fall, in dem der Angreifer Lesezugriff auf die Datenbank (die die Hashes enthält) hat, aber keinen Zugriff auf den Quellcode mit dem Pfeffer hat.

Ein typisches Szenario wäre SQL-Injection, weggeworfene Backups, verworfene Server ... Diese Situationen sind nicht so ungewöhnlich wie es sich anhört und oft nicht unter Ihrer Kontrolle (Server-Hosting). Wenn du benutzt...

  • Ein einzigartiges Salz pro Passwort
  • Ein langsamer Hashing-Algorithmus wie BCrypt

... starke Passwörter sind gut geschützt. Unter diesen Bedingungen ist es fast unmöglich, ein sicheres Passwort zu erzwingen, selbst wenn das Salz bekannt ist. Das Problem sind die schwachen Passwörter, die Teil eines Brute-Force-Wörterbuchs sind oder Ableitungen davon sind. Bei einem Wörterbuchangriff werden diese sehr schnell angezeigt, da Sie nur die gängigsten Kennwörter testen.

Die zweite Frage ist, wie man den Pfeffer aufträgt.

Eine häufig empfohlene Methode zum Anwenden eines Pfeffers besteht darin, das Kennwort und den Pfeffer zu kombinieren, bevor Sie ihn an die Hash-Funktion übergeben:

$pepperedPassword = hash_hmac('sha512', $password, $pepper);
$passwordHash = bcrypt($pepperedPassword);

Es gibt aber noch einen noch besseren Weg:

$passwordHash = bcrypt($password);
$encryptedHash = encrypt($passwordHash, $serverSideKey);

Dies ermöglicht nicht nur das Hinzufügen eines serverseitigen Geheimnisses, sondern auch den Austausch des $ serverSideKey, falls dies erforderlich sein sollte. Diese Methode erfordert etwas mehr Arbeit, aber wenn der Code einmal vorhanden ist (Bibliothek), gibt es keinen Grund, ihn nicht zu verwenden.


Sie würden also sagen, ein Pfeffer erhöht die Sicherheit gegenüber einem Salz, kurz gesagt? Vielen Dank für die Hilfe bei der Implementierung.
Glitch Desire

1
@LightningDust - Ja, bei schwachen Passwörtern, solange der Pfeffer geheim bleibt. Es verringert einige genau definierte Arten von Bedrohungen.
Martinstoeckli

@martinstoeckli definitiv ein guter Weg, um dies umzusetzen. Gut zu sehen, dass jemand mit Sicherheitserfahrung diese Methode unterstützt. Wäre ein MySQL- AES_ENCRYPT($passwordHash, $serverSideKey)Aufruf auch eine geeignete Möglichkeit, dies zu implementieren?
Foochow

1
@Foo_Chow - Ich kenne die Implementierung der MySQL-Funktion nicht, aber es scheint, dass sie den EBC-Modus verwendet haben, um den IV-Vektor zu vermeiden. Zusammen mit dem bekannten Klartext (Hash-Werte beginnen immer mit denselben Zeichen) könnte dies ein Problem sein. Auf meiner Homepage habe ich eine Beispielimplementierung veröffentlicht, die diese Verschlüsselung behandelt.
Martinstoeckli

@martinstoeckli interessant, nicht zu vertraut mit den Konzepten; Es scheint jedoch, dass eine IV für die robustesten Ergebnisse wünschenswert wäre. Scheint nicht viel Overhead für den zusätzlichen Nutzen hinzuzufügen.
Foochow

2

Der Sinn von Salz und Pfeffer besteht darin, die Kosten für eine vorberechnete Passwortsuche zu erhöhen, die als Regenbogentabelle bezeichnet wird.

Im Allgemeinen ist es schwierig, eine Kollision für einen einzelnen Hash zu finden (vorausgesetzt, der Hash ist sicher). Mit kurzen Hashes ist es jedoch möglich, mithilfe des Computers alle möglichen Hashes für eine Suche auf einer Festplatte zu generieren. Dies wird als Regenbogentisch bezeichnet. Wenn Sie eine Regenbogentabelle erstellen, können Sie in die Welt hinausgehen und schnell plausible Passwörter für jeden (ungesalzenen, nicht gepfefferten) Hash finden.

Der Sinn eines Pfeffers besteht darin, die Regenbogentabelle, die zum Hacken Ihrer Passwortliste benötigt wird, eindeutig zu machen. Dadurch wird mehr Zeit für den Angreifer verschwendet, um den Regenbogentisch zu konstruieren.

Der Sinn des Salzes besteht jedoch darin, die Regenbogentabelle für jeden Benutzer für den Benutzer eindeutig zu machen, was die Komplexität des Angriffs weiter erhöht.

In Wirklichkeit geht es bei der Computersicherheit fast nie darum, es (mathematisch) unmöglich zu machen, sondern nur mathematisch und physikalisch unpraktisch (zum Beispiel in sicheren Systemen würde die gesamte Entropie im Universum (und mehr) benötigt, um das Passwort eines einzelnen Benutzers zu berechnen).


Bietet Salz + Pfeffer also mehr Sicherheit als nur ein Salz? Oder wäre es besser, wenn ich den Pfeffer fallen lasse und mehr Verschlüsselungsiterationen durchführe?
Glitch Desire

2
Die Hauptsache an einer Regenbogentabelle ist, dass Sie keine für einen bestimmten Angriff erstellen, sondern eine bereits vorhandene herunterladen. Es gibt lange Regenbogentabellen für beliebte Hash-Algorithmen, nur einen Google entfernt!
Richard

1
@ LightningDust Ich kann mir selbst keinen Grund vorstellen. Richard im anderen Thread hat sich jedoch einen ausgedacht. Sie können den Pfeffer in Ihrem Quellcode verstecken, was bedeutet, dass Ihr Angreifer einen anderen Ort benötigt, um Zugriff zu erhalten, nur um eine Regenbogentabelle zusammenzustellen.
Aron

@Aron - Nun, das habe ich mir gedacht, da wir Anwendungsserver haben, die von Datenbankservern getrennt sind (das heißt, wenn Sie rootauf unseren Datenbankserver gelangen , haben Sie immer noch keinen Zugriff auf unseren Anwendungsserver), die Pfeffer im Quellcode verstecken (in unsere Konfigurationsdatei) würde zusätzliche Sicherheit bieten.
Glitch Desire

1

Das Speichern eines fest codierten Werts in Ihrem Quellcode kann nicht als sicherheitsrelevant angesehen werden. Es ist Sicherheit durch Dunkelheit.

Wenn ein Hacker Ihre Datenbank erwirbt, kann er Ihre Benutzerkennwörter brutal erzwingen. Es wird nicht lange dauern, bis dieser Hacker Ihren Pfeffer identifiziert, wenn er es schafft, ein paar Passwörter zu knacken.


1
Es würde eine vorberechnete Regenbogentabelle für eine ungesalzene Passworttabelle unbrauchbar machen. Kurz gesagt, selbst wenn der Angreifer Ihren Pfeffer kennen würde, müsste er einen neuen Regenbogentisch erstellen.
Aron

3
Es stärkt den Hash basierend auf Daten, die nicht in der Datenbank verfügbar sind, was eine gute Sache ist. Dinge in der Datenbank können möglicherweise in Schwachstellen aufgedeckt werden - es ist weniger wahrscheinlich, dass auf einen Wert im Code auf dieselbe Weise zugegriffen wird.
Richard

Salze sind Einwegfunktionen. Selbst wenn Sie ein Passwort erfolgreich erzwingen, erhalten Sie nur dieses Passwort und können den Pfefferwert nicht selbst ermitteln.
Glitch Desire

1
@ LightningDust Ich denke du meinst "Hashes sind Falltürfunktionen". Ja, es ist unmöglich, Salz und / oder Pfeffer aus einem sicheren Hash herauszufinden (tatsächlich ist dies die Definition eines sicheren Hashs).
Aron

6
@ Aaron Sicherheit durch Dunkelheit kann eine gültige Technik sein, die als Verteidigungsschicht verwendet wird. Der Punkt ist, dass es niemals als Verteidigung herangezogen werden sollte, sondern stattdessen verwendet wird, um "einen Angreifer zu verlangsamen". Wenn dies nicht der Fall wäre, würde so etwas wie ein Honigtopf nicht verwendet werden. Stattdessen können wir die Sicherheit durch Dunkelheit effektiv nutzen, um Angreifer zu verlangsamen, solange wir uns für die Sicherheit unserer Anwendung nicht darauf verlassen.
Ircmaxell
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.