Frage:
Ist es sicher / sinnvoll, ein Salz im selben Feld wie das Hash-Passwort zu speichern?
PenumbraBrah
2018-04-06 19:26:27 UTC
view on stackexchange narkive permalink

Bei der Verwendung von Argon2 zum Hashing von Kennwörtern in meiner Anwendung ist mir aufgefallen, dass eine Zeichenfolge wie diese generiert wird (z. B. für das Kennwort "rabbit"):

  $ argon2i $ v = 19 $ m = 65536, t = 3, p = 1 $ YOtX2 // 7NoD / owm8RZ8llw == $ fPn4sPgkFAuBJo3M3UzcGss3dJysxLJdPdvojRF20ZE =  

Mein Verständnis ist, dass alles vor p = ist Parameter, der Hauptteil des p = ist das Salt, und der letzte Teil ist das Hash-Passwort.

Ist es akzeptabel, dies in einem Feld in einer SQL-Datenbank zu speichern ( varchar (99) in diesem Fall) oder sollte die Zeichenfolge in ihre Bestandteile getrennt werden? Sollte ich das Salz getrennt vom Hash-Passwort speichern und die Parameter im Code behalten?

[sehr stark verwandt] (https://security.stackexchange.com/questions/17421/how-to-store-salt)
Wenn Sie ein [_pepper_] verwenden (https://security.stackexchange.com/questions/3272/password-hashing-add-salt-pepper-or-is-salt-enough), können Sie es außerhalb der Datenbank speichern.
Die PHP-Funktion [password_hash] (http://php.net/manual/en/function.password-hash.php) speichert das Salt auch mit der Hash-Zeichenfolge (z. B.: $ 2y $ 10 $.
"varchar (99)" scheint furchtbar eng.Was ist, wenn die nächste Version der Hash-Bibliothek Parameter hinzufügt oder den Hash verlängert?Hat Ihre Datenbank nicht "varchar (MAX)" oder ähnliches?
Sieben antworten:
Anders
2018-04-06 19:36:50 UTC
view on stackexchange narkive permalink

Sie sollten es in einem einzelnen Feld speichern. Versuchen Sie nicht, es in Teile zu unterteilen.

Ich weiß, dass dies für Personen mit Datenbankhintergrund, bei denen der Modus Operandi darin besteht, Daten zu normalisieren und serialisierte Zeichenfolgen zu verwenden, als hässlicher Hack angesehen werden kann. Aus Sicherheitsgründen ist dies jedoch durchaus sinnvoll.

Warum? Da die kleinste Einheit, an der der einzelne Entwickler arbeiten muss, diese vollständige Zeichenfolge ist. Das ist es, was die App an die Hash-Bibliothek übergeben muss, um zu überprüfen, ob ein angegebenes Passwort korrekt ist oder nicht. Aus Entwicklersicht kann die Hash-Bibliothek eine Black Box sein, und sie muss sich nicht darum kümmern, was diese lästigen Teile tatsächlich bedeuten.

Dies ist eine gute Sache, da die meisten Entwickler unvollkommene Menschen sind (ich weiß , weil ich selbst einer bin). Wenn Sie sie diese Saite auseinander nehmen lassen und dann versuchen, alles wieder zusammenzufügen, werden sie wahrscheinlich die Dinge durcheinander bringen, z. B. allen Benutzern das gleiche oder gar kein Salz geben.

Es ist auch eine schlechte Idee, nur die Parameter im Code zu speichern. Wenn Prozessoren schneller werden, möchten Sie möglicherweise in Zukunft den Kostenfaktor erhöhen. Während der Migrationsphase haben unterschiedliche Kennwörter unterschiedliche Kostenfaktoren. Sie benötigen also Informationen zur Passwortebene darüber, welcher Kostenfaktor zum Hashing verwendet wurde.

Viele kryptografische Bibliotheken verwenden das Geheimnis und das Salz als separate Parameter.Allein unter diesem Gesichtspunkt erscheint es ratsam, den Verdau und das Salz / die Entropie in getrennten Feldern zu lagern.Wenn Sie sie separat aufbewahren, müssen Sie nicht einmal eine einheitliche Länge für das Salz verwenden.Sie können Ihre Algorithmen versionieren und mehrere gleichzeitig unterstützen, sodass Sie Benutzer problemlos auf einen neueren, stärkeren Algorithmus umstellen können, ohne dass eine Kennwortänderung erforderlich ist, und so weiter.
@Craig Viele ältere Bibliotheken tun dies, aber ich würde sagen, dass es heutzutage als schlechtes Design angesehen wird.Bei Versionsalgorithmen können Sie dies auch mit der vollständigen Zeichenfolge in einer Spalte tun.
Deshalb liebe ich den Stapelaustausch.Jeden Tag lerne ich etwas, von dem ich nicht wusste, dass ich es nicht wusste.
Es ist nicht nur aus Sicht der Sicherheitspraxis sinnvoll.Unter dem Gesichtspunkt der Normalisierung ist dies aus den von Ihnen dargelegten Gründen immer noch sinnvoll.
Dies hat auch den Vorteil, zukunftssicher zu sein;Wenn Sie die Hashing-Parameter später ändern möchten, funktionieren alte Hashes in der Datenbank weiterhin _ (solange Sie die Bibliotheksfunktionen verwenden, um Hashes zu vergleichen, wie Sie es mit Argon2 tun sollten, anstatt die Hash-Strings direkt zu vergleichen) _
@Anders Welche Bibliothek unterstützt Ihrer Meinung nach die Versionierung des gespeicherten Passworts mit einem einzigen Passwortfeld?Ich kann sehen, wie es funktioniert, und der Ansatz hat den Reiz, aber ich habe noch nie einen in freier Wildbahn gesehen.
@Voo Beliebige Bibliothek.Alle Informationen, die Sie benötigen - Algorithmus, Parameter, Salt - befinden sich in der Zeichenfolge, die Sie in einer einzelnen Spalte speichern.
@Anders Es ist keine Blackbox mehr, wenn ich mein eigenes Format definieren muss, um die einzelnen Teile in einer einzelnen Zeichenfolge zu speichern, und zwischen dem Tupel (Algorithmus, Hash, Salt) und der Zeichenfolge selbst konvertieren muss.Wenn irgendetwas, das es viel wahrscheinlicher macht, Fehler einzuführen.Ich dachte, die ganze Idee war zu vermeiden, dass der Entwickler sich mit den einzelnen Teilen befassen muss?
@Voo Ja, es geht darum, die Zeichenfolge nicht zu ändern.TU das niemals.Das wollte ich nicht vorschlagen.Ich denke, wir verstehen uns falsch.
@Voo Spring-Security Version 5 geht in diese Richtung: https://docs.spring.io/spring-security/site/docs/current/reference/html/core-services.html#pe-dpe.Die einzige fehlende Funktionalität besteht darin, dass die Bibliothek der Anwendung nicht die Möglichkeit bietet, das Feld für das Hash-Kennwort auf das Standardcodierungsschema zu migrieren (wenn es nicht verwendet wird).
Wenn Sie nach einem Beispiel für eine Bibliothek suchen, in der alle Parameter, einschließlich des Algorithmus, transparent in einer Zeichenfolge gespeichert sind und ein reibungsloses Upgrade auf stärkere Einstellungen ermöglicht, lesen Sie die [PHP-Funktionen password_ *] (http://php.net/password)), einschließlich der Beispiele für [password_needs_rehash] (http://php.net/manual/en/function.password-needs-rehash.php).
@Voo Diese Versionierung muss vom Entwickler ausgelöst werden, aber das Dekodieren und Neukodieren wird vollständig von der Bibliothek übernommen.
@Anders Ich war daran interessiert, welche Bibliotheken tatsächlich eine API haben, die mit einer einzelnen Zeichenfolge anstelle des üblichen Tripels funktioniert.Man braucht in diesem Fall schließlich eine zusätzliche Konfiguration.Die Frühlings-API ist ziemlich interessant anzuschauen.
@Voo Eine weitere Implementierung zur Kennwortverschlüsselung, bei der alle drei Teile als einzelne Zeichenfolge gespeichert werden, ist [bcrypt] (https://en.wikipedia.org/wiki/Bcrypt) mit Implementierungen für zahlreiche Sprachen.
Machavity
2018-04-06 22:34:26 UTC
view on stackexchange narkive permalink

Was Sie vermissen, ist, dass Hashes mit den Originaldaten abzüglich der Originalzeichenfolge funktionieren. Wenn Sie eine Zeichenfolge anhand eines Hashs validieren möchten, nehmen Sie die angegebene Zeichenfolge sowie die ursprünglichen Hash-Daten (Kosten, Salz usw.) und generieren einen neuen Hash. Wenn der neue Hash mit dem alten übereinstimmt, wird die Zeichenfolge validiert (mit anderen Worten, die Zeichenfolge wird niemals entschlüsselt , sie wird erneut aufbereitet ).

Das Salz zu haben hilft dir nicht bei roher Gewalt. Das Salz ist ein wesentlicher Bestandteil eines Hashs, genauso wie Becher Teil eines Schlosses sind. Wenn Sie eines herausnehmen, kann es niemand verwenden.

Das Trennen des Speichers ist sinnlos. In den meisten Fällen müssen Sie den fertigen Hash wieder zusammensetzen, um ihn zu validieren. Aus diesem Grund werden alle Komponenten standardmäßig in einer praktischen Zeichenfolge gespeichert.

Sie haben es viel eleganter erklärt als ich, in weniger Worten.+1
Ja, das Trennen ist sinnlos - Sie können keines ohne das andere verwenden, Sie aktualisieren niemals eines ohne das andere und sie haben identische Sicherheitsanforderungen. Behandeln Sie also salt + password als eine einzige unteilbare Einheit für die Speicherung.
keithRozario
2018-04-06 22:00:48 UTC
view on stackexchange narkive permalink

Ja, Sie können es in einem einzelnen Feld speichern, und viele Datenbanken / Anwendungen speichern den Salt + Hash in einem einzelnen Feld / einer einzelnen Datei usw.

Das bekannteste ist Linux (das ist kein DB), der den Hash in der Datei / etc / shadow im folgenden Format speichert:

"$ id $ salt $ hashed", die druckbare Form eines Passwort-Hash, wie er von crypt (C) erstellt wurde. , wobei "$ id" der verwendete Algorithmus ist. (Unter GNU / Linux steht "$ 1 $" für MD5, "$ 2a $" für Blowfish, "$ 2y $" für Blowfish (korrekte Behandlung von 8-Bit-Zeichen), "$ 5 $" für SHA-256 und "$ 6 $" "ist SHA-512, [4] andere Unix-Versionen haben möglicherweise andere Werte wie NetBSD.

(Quelle: https://en.wikipedia.org/wiki/Passwd)

Das Salz soll nicht geheim sein (oder zumindest nicht geheimer als der Hash). Sein Hauptzweck ist es, Brute-Forcing-Angriffe viel schwieriger zu machen, da der Angreifer a verwenden muss Unterschiedliches Salz für jeden einzelnen Benutzer.

Ihre Frage ist jedoch differenzierter - weil Sie nicht nur nach Salzen, sondern auch nach Parametern fragen. Dinge wie der Hashing-Algorithmus, die Iterationszahl und das Salz Speichern Sie dies nicht im Code, sie gehören immer noch in die Datenbank.

Stellen Sie sich vor, Sie haben eine Reihe von Benutzern und Sie haben SHA1 als Hashing-Algorithmus verwendet. Ihr Datenbankfeld würde dies also tun Seien Sie so etwas wie SHA1: SALZ: HASH .

Wenn Sie Ihre Datenbank auf BCRYPT aktualisieren möchten, wie würden Sie dies tun?

Typi Normalerweise würden Sie Code bereitstellen, damit Sie bei der Anmeldung eines Benutzers das Kennwort überprüfen und, falls gültig, das Kennwort mit einem neueren Algorithmus erneut hashen. Jetzt sieht das Feld für den Benutzer folgendermaßen aus: BCRYPT:SALT:HASH .

Aber dann wären einige Benutzer auf SHA1 und andere auf BCRYPT, und da dies bei a ist Auf Benutzerebene benötigen Sie die Parameter, die Ihrem Code mitteilen, welche Benutzer sich in der Datenbank befinden sollen.

Kurz gesagt, das Speichern der Parameter und des Hashs in einem einzelnen Feld ist in Ordnung, aber das Aufteilen aus irgendeinem Grund (Effizienz, einfacher Code usw.) ist ebenfalls in Ordnung. Was nicht in Ordnung ist, ist dies in Ihrem Code zu speichern :)

TL: DR

Troy Hunt hat kürzlich einen Podcast veröffentlicht, in dem vorgeschlagen wird, dass es effektiver ist, einfach alle derzeit vorhandenen SHA1-Hashes zu verwenden, anstatt wie oben beschrieben zu BCRYPT zu migrieren die Datenbank und hashen Sie sie mit BCRYPT.

Effektiv BCRYPT(SHA1(clear_password))

Wenn sich ein Benutzer anmeldet, würden Sie

  BCRYPT (SHA1 (clear_password)) == <db_field>  

Auf diese Weise wird jeder auf der Plattform gleichzeitig aktualisiert, und Sie haben keine Datenbank mit mehreren Hashs Formate für Passwörter. Sehr sauber und sehr nett.

Ich denke, diese Idee ist absolut sinnvoll, aber obwohl jeder auf einmal migriert, ist sie nicht sofort. Sofern Sie nicht bereit sind, Ausfallzeiten in der App zu akzeptieren (während Sie alle Kennwörter erneut hashen), wird es immer noch eine kleine Zeitspanne geben, in der sich einige Benutzer auf BCRYPT und andere auf SHA1 befinden. Daher sollte Ihre Datenbank die weiterhin speichern Parameter des Hashing-Algorithmus, und Ihr Code würde basierend darauf ausgeführt.

Sie kennen die Sache [Warum sollten wir nicht unsere eigenen rollen?] (Https://security.stackexchange.com/q/18197/114527)?Wurde nachgewiesen, dass BCRYPT (SHA1 ()) dieses Problem nicht hat?(Sie haben keinen Link angegeben, damit ich leicht nachforschen kann, und "macht vollkommen Sinn" ist nicht dasselbe wie "es ist wahr, dass".)
Nun, ich habe den Satz mit "Ich denke" eingeschränkt, es macht vollkommen Sinn :).Mein Verständnis ist, dass wenn BCRYPT Brute-Force teurer macht, unabhängig davon, was die Eingabe ist, ob es sich um eine SHA1 oder den Klartext handelt, die Brute-Force für den Angreifer immer noch teurer ist.Das BCRYPT (SHA1 ()) ist aus Migrationssicht sinnvoll.
Außerdem habe ich hier dieses Thema gefunden, das Ihnen einige andere Anwendungsfälle für die SHA-Eingabe eines Kennworts vor der BCRYPT-Eingabe vorschlägt.Allgemeiner Konsens des Threads war, dass es in Ordnung ist, aber vielleicht sollten wir eine separate Frage stellen, wenn Sie immer noch nicht einverstanden sind https://security.stackexchange.com/questions/61595/is-it-good-practice-to-sha512-passwörter-bevor-sie-an-bcrypt übergeben
@keithRozario "Es ist intuitiv offensichtlich, dass BCRYPT (SHA1 (x)) mindestens so sicher ist wie BCRYPT (x)" ist nicht dasselbe wie "es gibt einen Sicherheitsnachweis dafür, dass ...".Erste Regel der Kryptographie: Vertraue niemals deiner Intuition, es sei denn, dein Name ist djb oder ähnlich.
@MartinBonner ist korrekt.Es ist intuitiv, aber es ist auch falsch.Angenommen, SHA1 ist defekt.Simulieren Sie dies, indem Sie für alle Eingaben 1 zurückgeben.BYCRYPT (SHA1 (x)) ist in diesem Szenario deutlich weniger sicher als BCRYPT (x). Betrachten Sie auch SHA1 (BCRYPT (x)).Abhängig davon, * wie * SHA1 gebrochen ist, können die Hashes * gültig bleiben.Aber es wird niemals sicherer sein, als nur das sicherere der beiden zu verwenden.Da sie im Idealfall die gleichen Parameter in der Sicherheitsgleichung beeinflussen.* Wenn * sie eine minimale Interaktionsverkettung hätten, könnte dies nützlich sein, aber das ist eine Menge Mathe.Daher * bewiesen * @ AndrewMorton
@AndrewMorton Gute Diskussion, aber ich bin nicht überzeugt.Ihr Beispiel für die Simulation eines fehlerhaften SHA1, bei dem für alle Eingaben 1 zurückgegeben wird, ist nicht korrekt. Wenn der Benutzer 1 für sein Kennwort auswählt, ist BCRYPT fehlerhaft.Aber ich beginne einen anderen Thread, weil ich das interessant finde.
Der neue Thread ist hier: https://security.stackexchange.com/questions/183358/how-secure-is-bcryptsha1password
@keithRozario Das hat Black geschrieben.
TTT
2018-04-07 00:27:25 UTC
view on stackexchange narkive permalink

Aus Sicherheitsgründen spielt es keine Rolle, ob das Salt- und das Hash-Passwort in einem einzelnen Feld oder in separaten Feldern gespeichert sind, obwohl ich mich der Einfachheit halber zu einem einzelnen Feld neigen würde. Der einzige Grund, sie zu trennen, besteht darin, dass Ihr Anwendungscode das Salt und das Kennwort separat an die Validierungsfunktion übergeben muss. Wenn für Ihren Anwendungscode nur eine einzige kombinierte Zeichenfolge erforderlich ist, können Sie diese auch so speichern.

Beispielsweise hat die ältere ASP.NET-Mitgliedschaft den Kennwort-Hash und das Salt in zwei DB-Felder aufgeteilt Die neuere ASP.NET-Identität enthält Hash und Salt in einem einzelnen DB-Feld. Die neueren Funktionen wurden geändert, um die einzelne Zeichenfolge als Ein- und Ausgabe zu behandeln.

Andrew Morton
2018-04-08 00:36:49 UTC
view on stackexchange narkive permalink

Ist es akzeptabel, dies in einem Feld in einer SQL-Datenbank zu speichern (in diesem Fall varchar (99))

Nein. Die Größe der Daten kann sich irgendwann ändern. Ein Varchar (MAX) -Feld sollte verwendet werden, es sei denn, die Spezifikationen geben an, dass die Größe immer genau 99 beträgt und es keine Abweichungen von diesem jemals geben darf. Lassen Sie die Datenbank sich um die Speicheranforderungen kümmern.

ArtisticPhoenix
2018-04-08 05:42:05 UTC
view on stackexchange narkive permalink

Um zu wissen, ob es mehr oder weniger sicher ist, müssen wir den Zweck eines Salzes verstehen.

Ein Salz dient einigen Zwecken (an die ich denken kann)

  1. Wörterbuchangriffe verhindern
  2. ol>

    Bei einem Wörterbuchangriff wird ein logisches Wort als Teil eines Kennworts verwendet. Der Archetyp ist das Wort Passwort oder sogar P @ ssW0rd . Menschen sind unvollkommen und es fällt ihnen leichter, sich an Wörter zu erinnern, als an zufällige Buchstaben- und Zahlenfolgen. Ein Wörterbuchangriff beruht darauf, um den Weg eines Brute-Force-Angriffs zu verkürzen. Wenn wir einen zufälligen Teil hinzufügen, macht dies diese Art von Angriff offensichtlich unmöglich oder sinnlos und bringt sie wieder dazu, das Ganze brutal zu erzwingen.

    Wenn ein Angreifer das verwendete Salt kennt, muss er alle seine Wörterbuchdateien für jedes Kennwort bearbeiten. Dies setzt voraus, dass er weiß, wie das Salt zum ursprünglichen Kennwort hinzugefügt wird. Ein großer Vorteil einer Wörterbuchliste besteht darin, dass Sie 1000 Passwörter und 1 Million Wörterbuchwörter verwenden. Dann durchlaufen Sie sie und versuchen, ein paar Übereinstimmungen mit schwächeren Passwörtern zu erhalten. Es ist also nicht wirklich praktisch, 1 Million Wörter 1000 Mal bearbeiten zu müssen.

    1. Verhindern Sie Hash- oder Rainbow-Tabellenangriffe.
    2. ol>

      A. In der Rainbow-Tabelle werden Hashes vorberechnet und in einer Datenbank gespeichert. Zum Beispiel könnten Sie MD5 nehmen und einfach anfangen, zufällige Dinge zu hashen und zu speichern. Wenn Sie dann ein Passwort knacken möchten, schauen Sie einfach in der Regenbogentabelle nach.

      Wenn ein Angreifer das Salz hat, muss er die Regenbogentabelle für jedes verwendete Salz neu kompilieren. Der Vorteil dieses Angriffs besteht darin, dass diese Daten im Voraus zusammengestellt und immer wieder verwendet werden. Dies versetzt sie wieder in die Lage, das Passwort brutal zu erzwingen. Wenn Sie alle Passwörter unterschiedlich salzen und salzen, bedeutet dies im Grunde, dass Sie die Regenbogentabelle für jedes Salz neu berechnen müssen. Aus diesem Grund ist es wichtig, für jedes Passwort unterschiedliche Salze zu verwenden.

      Summery

      Keiner dieser Gründe hängt wirklich davon ab, dass das Salz geheim ist. Offensichtlich sind sie alle weniger stark, wenn ein Angreifer das Salz kennt. Aber zusätzliche Informationen, die sie erhalten, helfen ihnen immer. Ich würde also nicht sagen, dass ich Werbung machen soll, aber es gibt ein Sprichwort über Sicherheit, die auf Dunkelheit basiert ...

      Haftungsausschluss Ich bin keineswegs ein kryptologischer Experte, aber Dies sind einige der wichtigsten Gründe, die mir einfallen, wenn ich an Salze denke.

      Ich hoffe, das hilft.

Sie liegen falsch in Grund drei.Das Salt ist öffentlich, so dass der Angreifer weiterhin alle 1-Zeichen-Passwörter, alle 2-Zeichen-Passwörter usw. durcharbeiten kann. Das * einzige *, was ein Salt tut, ist, dass der Angreifer jeweils einen Benutzer bearbeiten muss.
@MartinBonner - gut, ich habe es entfernt ...
maggick
2018-04-06 19:36:48 UTC
view on stackexchange narkive permalink

Das Salt wird nur verwendet, um die Angriffe der Regenbogentabellen zu blockieren. Daher wird Ihr Salt möglicherweise mit dem Hash-Passwort gespeichert, wie dies auf dem neuesten GNU / Linux-System der Fall ist, auf dem das Salt in / etc / shadow gespeichert ist.

Ich bin nicht sicher, wie Ihre Antwort auf verschiedene Datenbankspalten zutreffen würde.


Diese Fragen und Antworten wurden automatisch aus der englischen Sprache übersetzt.Der ursprüngliche Inhalt ist auf stackexchange verfügbar. Wir danken ihm für die cc by-sa 3.0-Lizenz, unter der er vertrieben wird.
Loading...