Frage:
Wie funktioniert das Speichern von Hash-Passwörtern?
Allahjane
2016-04-13 21:31:39 UTC
view on stackexchange narkive permalink

In normalen Netzwerkanwendungen, die Kennwort-Hashing verwenden, wird das Benutzerkennwort auf der Clientseite gehasht, bevor es an den Server gesendet wird, oder wird es ohne Hashing als Verschlüsselung des Nur-Text-Kennworts an den Server gesendet?

Die Hauptfrage, die ich habe, ist, ob ein Angreifer die Hash-Passwörter entdeckt. Warum kann er dann nicht einfach Hash an den Server senden, um sich bei clientseitigem Hashing zu authentifizieren?

[Diese Frage] (http://security.stackexchange.com/questions/58704/can-client-side-hashing-reduce-the-denial-of-service-risk-with-slow-hashes) enthält einige verwandte Informationenkann nützlich finden
Für Webanwendungen gelten die unten vorgeschlagenen Lösungen gut.Auch JavaScript kann nicht als vertrauenswürdig eingestuft werden, da es ersetzt werden kann, wenn der Server angegriffen wird.Die Frage lautet nicht "Webanwendungen": Warum wird Secure Remote Password nicht für Anwendungen verwendet (und ist dies nicht der Standard), bei denen Codesicherheit und Leistung keine Probleme darstellen?
Bitte werfen Sie einen Blick auf https://security.stackexchange.com/q/8596/971, https://security.stackexchange.com/q/23006/971, https://security.stackexchange.com/q/3323/ 971, http://security.stackexchange.com/q/211/971, http://security.stackexchange.com/q/51959/971.Ihre Frage scheint durch das dortige Material beantwortet zu werden.In Zukunft ermutige ich Sie, mehr Nachforschungen anzustellen, bevor Sie fragen.Es gibt viele großartige Materialien auf dieser Website - versuchen Sie, sie zu durchsuchen, bevor Sie fragen, und Sie werden möglicherweise feststellen, dass die Antwort bereits erklärt wurde!
Ailiuiefir CMT.W.neveeeeerrrrr!
Fünf antworten:
Thomas Pornin
2016-04-13 21:42:55 UTC
view on stackexchange narkive permalink

Mindestens ein Teil des Hashings muss serverseitig erfolgen. Unabhängig davon, was der Client an den Server sendet, wird Zugriff gewährt. Wenn also derselbe Wert nur so wie er ist auf dem Server gespeichert wird, treten dieselben Probleme wie bei der Speicherung von Klartextkennwörtern auf, nämlich ein einziger schreibgeschützter Blick auf Ihren Server Die Datenbank bietet alle Zugriffe.

In den meisten Fällen wird das gesamte Hashing auf dem Server durchgeführt, da der Client ein Webbrowser ist, der bestenfalls Javascript ausführen kann, und Javascript ist bei kryptografischen Aufgaben nicht sehr gut. Der Client sendet das Kennwort selbst (natürlich über HTTPS), und der Server berechnet den Hash und vergleicht ihn mit dem gespeicherten Hashwert. Der Angreifer kann den Hash nicht einfach "weitergeben". Er muss einen Wert senden, der beim Hashing durch den Server den gespeicherten Hashwert ergibt.

Wenn die Clients gut darin sind, Krypto zu erstellen (z. B. ein schwerer nativer Client für ein Spiel), dann der Großteil des Der Hashing-Prozess kann auf der Clientseite durchgeführt werden, es muss jedoch noch eine endgültige Hash-Berechnung auf dem Server durchgeführt werden.

** Javascript ist nicht sehr gut für kryptografische Aufgaben ** Sie meinen, die Leistung wäre ein Problem?Aber wie intensiv könnte es sein, ein 8-20-stelliges Passwort zu hashen, das die Kundenerfahrung beeinträchtigen würde?
Die Theorie des Passwort-Hashing ist, dass es rechenintensiv sein muss;Siehe [diese Antwort] (http://security.stackexchange.com/questions/211/how-to-securely-hash-passwords/31846#31846).Die Verwendung einer Sprache mit geringer Leistung impliziert ein kostengünstigeres Hashing, was Wörterbuchangriffe erleichtert.Über Leistungsprobleme hinaus verwendet Javascript ein Rechenmodell, von dem bekannt ist, dass es Krypto-Implementierungen erschwert (z. B. kein echter Integer-Typ).
Wenn Sie das Client-Hash-Passwort zulassen, können Sie Salt nicht mehr verwenden und können Angriffe erneut abspielen (was bringt Hashing, wenn Sie ihm nicht vertrauen?), Es sei denn, Sie implementieren ein komplexes CHAP.Ich denke, das Denunzieren von Hashing in JavaScript erfolgt aufgrund der Schwächen des JavaScript-Schutzes, nicht weil es in irgendeiner Weise an Leistung mangelt (was stark von der Browser-Implementierung und der CPU abhängt).Hier ist ein Artikel, der die meisten Grundlagen abdeckt: https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful/
@JeffMeden Das ist richtig, weshalb der Server den größten Teil des Hashings durchführen muss.Das Vor-Hashing einer kleinen Client-Seite kann jedoch dazu beitragen, dass beim Schnüffeln nicht das Nur-Text-Passwort abgerufen wird, was angesichts der Wiederverwendung des Passworts eine gute Sache ist.
@JeffMeden Warum?Der Server kann immer noch ein Salz verwenden, um seinen Teil des Hashings zu erledigen.Client-Hashing bedeutet einfach, dass selbst wenn das Passwort aus irgendeinem Grund abgefangen wird, Sie das echte Klartext-Passwort nicht sehen können, was, wie AstroDan sagt, zumindest bei der Wiederverwendung von Passwörtern * hilft *.Möglicherweise haben Sie etwas Zeit, um Ihr Kennwort für andere Konten zu ändern.Nicht viel, aber besser als gar nichts.
@baikuru Die Sache ist, dass das Abfangen eines Hashs genauso gut ist wie das Abfangen des Kennworts (um dieses Konto zu gefährden), es sei denn, der Server fordert den Client heraus (d. H. Eine Version von CHAP), da der Server denselben Hash erwartet, egal was passiert.Es ist nobel, dies zu tun, um * andere * Konten zu sichern, aber ich bezweifle wirklich, dass dies jemals jemand tut.Die Geschichte des clientseitigen Hashings endete so ziemlich mit dem Aufkommen von billigem, zuverlässigem SSL / TLS.
@Allahjane Nicht nur wegen der Leistung ist Javascript eine schlechte Wahl für die Kryptographie.Dies liegt auch daran, dass ein Angreifer, der den Server steuern oder TLS unterbrechen kann, ohnehin beliebigen Javascript-Code an den Client senden kann.In fast jedem Szenario ist es unmöglich, die Sicherheit durch Kryptografie in Javascript zu verbessern.
@JeffMeden Clientseitiges Hashing verhindert nicht die Verwendung von Salz.Der Server kann einen Salt-Wert an den Client senden.
@kasperd Ich weiß, deshalb habe ich gesagt, * es sei denn, Sie implementieren eine Form von CHAP *, die zwar möglich ist, in JavaScript jedoch aus vielen Gründen wackelig ist, sodass es allgemein vermieden wird, nur TLS zu vertrauen
@Lasagna - das klingt nach einer großartigen neuen Frage!
@ThomasPornin (z. B. kein echter Integer-Typ) Implementierungsspezifische Verallgemeinerung.Sie haben offensichtlich noch nie gesehen, dass die Unreal-Engine nach der Kreuzkompilierung von JS zu Native mit Enscripten / asm.js in einem Browser ausgeführt wird
@JeffMeden Der Grund, warum Sie keinen Hash auf dem Client haben, ist eigentlich ganz einfach.Das clientseitige Hashing entspricht der Verwendung des Hash als Kennwort.Für Bruteforcing sende ich einfach jeden möglichen Hashed Value (ich muss keine Berechnung durchführen).Wenn Sie die Passwortdatenbank verlieren, können Sie sich mit den Hashes in der Datenbank anmelden.Grundsätzlich verlieren Sie ALLE Vorteile des Hashings.
Mark Buffalo
2016-04-13 22:16:25 UTC
view on stackexchange narkive permalink

Wie das Anmeldekennwort-Hashing funktionieren soll

Beachten Sie, dass ich in allen Snippets absichtlich Sicherheitsfunktionen ausschließe, weil ich es kompakt halten möchte. Verlassen Sie sich bei nichts auf diese Codefragmente.

In normalen Netzwerkanwendungen, die Kennwort-Hashing verwenden, wird das Benutzerkennwort auf der Clientseite gehasht, bevor es an den Server gesendet wird, oder es wird ohne Hashing gesendet als Verschlüsselung des Nur-Text-Passworts für den Server?

Nein, es ist eine gehashte Serverseite. Sie senden das Kennwort im Klartext oder über HTTPS an den Server. Der Server generiert dann einen Hash für das Kennwort wie folgt:

  public void RegisterAccount (Zeichenfolgenbenutzername, Zeichenfolgenkennwort, Zeichenfolgen-E-Mail) {if (! Database.EmailExists (E-Mail) &&! Database .UsernameExists (Benutzername)) {Database.AddNewUser (Benutzername, Hash.GenerateHash (Passwort), E-Mail); }}  

Angenommen, Database.AddNewUser (Zeichenfolge, Zeichenfolge, Zeichenfolge); fügt den Benutzernamen, das Hash-Kennwort und die E-Mail in die Datenbank ein. Der Hash wird basierend auf dem Passwort generiert.

Nehmen wir an, Sie geben als Passwort "Hack mich bitte nicht" ein. bcrypt verwandelt daraus $ 2a $ 08 $ BOHyNdXAVkWOUgPG / hvsjew7ZpngqJIgueY6m76xd4y3UllXUZLBy oder eine andere Variante, die auf dem Salz basiert. Die Datenbank sieht jetzt folgendermaßen aus:

  + -------------- + ----------------- ----------------------------------------- + ---- ---------------- + | Benutzer | Passwort | E-Mail | + -------------- + -------------------------------- ------------------------------ + ------------------- - + | markbuffalo | $ 2a $ 08 $ BOHyNdXAVkWOUgPG / hvsjew7ZpngqJIgueY6m76xd4y3UllXUZLBy | mark@buffalo.gov | + -------------- + ---------------------------- ---------------------------------- + --------------- ----- +  

Normalerweise rufen Sie die Datenbank auf, um das Kennwort für diesen Benutzernamen zu lesen. Sobald Sie die Datenbank aufgerufen haben, verwenden Sie eine Funktion wie Hash.ValidateHash () , um festzustellen, ob sie übereinstimmt. Wenn es übereinstimmt, können Sie sich mit diesem nicht gehashten Passwort anmelden.


Warum können Sie den Hash nicht einfach übergeben, um sich anzumelden?

In einigen sehr unglücklichen Fällen.

Die Hauptfrage, die ich habe, ist, ob ein Angreifer die Hash-Passwörter entdeckt. Warum kann er dann nicht einfach Hash an den Server senden, um sich bei clientseitigem Hashing zu authentifizieren?

Dies ist möglich, kann jedoch nur in schweren Fällen von massiv epischen Fehlern im Auftrag der Entwickler auftreten. Tatsächlich habe ich das schon einmal gesehen und ich werde Ihnen zeigen, wie dies über Code geschehen kann:

  public void Login (String-Benutzername, String-Passwort) {if (Database.LoginMatches ( Benutzername, Passwort) || Database.LoginMatches (Benutzername, Hash.ValidateHash (Passwort))) {logMeIn (); }}  

Im obigen Snippet möchte der Login überprüfen, ob entweder der Benutzer den Hash oder das Kennwort hat, das in dem in der Datenbank gespeicherten Hash validiert wird. Dies ist nicht der richtige Weg, dies zu tun. Tatsächlich ist es einer der schlimmsten Fälle von epischem Versagen, die ich je in meinem Leben gesehen habe.

Mit diesem Code können Sie einfach den Hash oder das Passwort eingeben und sich anmelden Tabelle. Eine der folgenden Anmeldungen funktioniert ordnungsgemäß:

  1. Login ("markbuffalo", "$ 2a $ 08 $ BOHyNdXAVkWOUgPG / hvsjew7ZpngqJIgueY6m76xd4y3UllXUZLBy");
  2. Login ("markbuffalo", @ "hack mich bitte nicht");
  3. ol>

    Das ist der falsche Ansatz. Es soll nicht passieren. Beim. Alles. Trotzdem haben einige Entwickler diesen Ansatz aus Gründen gewählt, die ich nicht kenne.


    Was ist der richtige Ansatz für die Hash-Validierung?

    Wie Rápli András sagte, stimmt h (x) nicht mit h (h (x)) überein. Der richtige Ansatz besteht darin, das eingehende Kennwort anhand des Hashs zu überprüfen, um festzustellen, ob sie übereinstimmen. Wenn sie nicht übereinstimmen, verwenden Sie keine ODER Magie ( || ). Erlauben Sie ihnen einfach nicht, sich anzumelden.

Ein wahrscheinlicher Grund für Code wie den oben gezeigten ist eine Migrationsstrategie.Wenn eine Anwendung Kennwörter nicht hasht und dann Unterstützung für Hashing hinzufügt, werden möglicherweise noch nicht alle in der Datenbank gespeicherten Kennwörter gehasht, sodass möglicherweise beide unterstützt werden müssen.Aber ich würde erwarten, dass das nur vorübergehend ist.Sie sollten diesen Code nicht für immer leben lassen müssen.Das Ziel sollte sein, alle Passwörter so schnell wie möglich zu hashen und dann diesen Code zu entfernen.
@Brandon Diese Art von Migrationsstrategie würde mir Tuberkulose verursachen.:-P Dies ist eine sehr einfache Lösung, um die Passwörter richtig zu hashen.Wenn Sie einen anderen Hash-Algorithmus verwenden, können Sie entweder verlangen, dass Benutzer ihre Kennwörter zurücksetzen, * oder * Sie können während der Migration etwas wie "Hash.ValidateOldHash (Kennwort)" verwenden.Wenn sich die Kennwörter im Klartext befinden, können Sie erneut verlangen, dass Benutzer ihre Kennwörter zurücksetzen, oder Sie können den Klartext in den entsprechenden Hash konvertieren und die Benutzerlistendatensätze für alle Benutzer automatisch aktualisieren.
Ich habe kürzlich ein System von sha1-Hashing auf bcrypt konvertiert. Um es für die Benutzer nahtlos zu gestalten, mussten wir die Passwörter nicht zurücksetzen.Wir haben alle vorhandenen sha1-Hashes über bcrypt ausgeführt und der Datenbank die Spalte "migrated = false" hinzugefügt.Wenn wir uns anmelden, überprüfen wir diese Spalte und führen dann entweder "verify_bcrypt (passwd)" oder "verify_bcrypt (sha1 (passwd))" aus (um das beschriebene Problem der Anmeldung mit Hash zu vermeiden).Wenn "migriert" bei erfolgreicher Anmeldung falsch war, führen wir "bcrypt (passwd)" durch, ersetzen den alten Hash und setzen "migrated = true".
@Alex Bingo!Gut gemacht.
Rápli András
2016-04-13 21:35:24 UTC
view on stackexchange narkive permalink

Zu Ihrer ersten Frage:

Dies hängt von der Anwendung ab. In den meisten Fällen wird das Kennwort im Klartext an den Server gesendet (und dies ist unsicher, wenn die Anwendung ein unverschlüsseltes Protokoll wie HTTP verwendet). Der Server speichert jedoch möglicherweise einen Hash-Wert in der Datenbank. In diesem Fall berechnet die Anwendung den Hashwert des vom Benutzer empfangenen Klartextkennworts und vergleicht ihn mit dem in der Datenbank gespeicherten Wert.

Zu Ihrer zweiten Frage:

Der Server erwartet eine Kennworteingabe: X . Der Angreifer findet irgendwie heraus, dass h (X) . Wenn er diesen Hash-Wert zur Authentifizierung eingeben würde, würde die Hash-Funktion erneut gegen h (x) ausgeführt er würde nicht einsteigen können, da h (x) nicht mit h (h (x)) übereinstimmt.

jcaron
2016-04-14 21:35:27 UTC
view on stackexchange narkive permalink

Wie andere bereits betont haben, sendet der Client das Klartext-Passwort normalerweise über einen sicheren Kanal (der reversible Verschlüsselung verwendet, kein Hashing ) und dieses Passwort wird dann serverseitig mit demselben Salt wie der gespeicherte Hash gehasht.

  Client < ----- Sicherer Link ----- > ServerCleartext-Passwort Verschlüsseltes Passwort Hashed-Passwort  
  1. Client hat das Klartext-Passwort.
  2. Client verschlüsselt Passwort (über TLS)
  3. Server empfängt verschlüsseltes Passwort, entschlüsselt es (über TLS)
  4. Server-Hash-Passwort mit demselben Salt wie in der Datenbank für diesen Benutzer gespeichert
  5. Server vergleicht berechneten Hash mit gespeichertem Hash.
  6. ol>

    Schutz:

  • gegen Abhören (aufgrund der Verwendung eines sicheren Kanals)
  • gegen MITM-Angriffe (wenn die TLS-Sitzung ordnungsgemäß eingerichtet, Zertifikate ordnungsgemäß überprüft usw.)
  • gegen Diebstahl von Passwortdatenbanken

Jetzt die Problem ist, wenn Sie ein Kennwort über einen Kanal senden müssen, der keine Verschlüsselung bietet , wie dies bei einem Protokoll auf niedriger Ebene (z. B. PPP oder 802.1X) der Fall sein kann. Die traditionellen Optionen (für PPP) waren:

  • PAP: Senden Sie das Kennwort im Klartext, das dann zum Vergleich mit dem serverseitig gehasht werden kann Hash-Passwort-Datenbank

  • CHAP: Verwenden Sie ein Challenge-Response-Protokoll und senden Sie eine Hash-Version des Passworts (kombiniert mit der Challenge und einer ID) über Der Link erforderte jedoch, dass der Server den Klartext der Passwörter speichert.

Ersteres schützt also vor Diebstahl von Passwortdatenbanken, jedoch nicht vor Abhören, während die Situation umgekehrt ist Letzteres.

Abgesehen von EAP-Protokollen, die tatsächlich einen TLS-Tunnel (PEAP, EAP-TTLS, EAP-TLS ...) einrichten, um den Kennwortaustausch zu sichern, gibt es ein alternatives Protokoll, das das Senden eines nicht umkehrbaren "Hash" von ermöglicht das Kennwort für einen Server, auf dem auch ein "Hash" des Kennworts gespeichert ist: SRP und allgemeiner "erweiterte PAKE" - Protokolle.

Ken
2016-04-14 23:43:01 UTC
view on stackexchange narkive permalink

Ein Angriff, der auf dem einfachen erneuten Senden erfasster Daten basiert (z. B. ein vom Client gehashtes Kennwort), ohne dass die Daten entschlüsselt werden müssen, wird als "Wiederholungs" -Angriff bezeichnet. Die Standardminderung für diesen Angriff besteht darin, ein sogenanntes "Nonce" in die Hash-Daten aufzunehmen. Dies kann eine vom Server bereitgestellte Zufallszahl oder ein vom Client generierter Zeitstempel mit angemessen hoher Auflösung sein. Der Server überprüft dann, ob die Nonce gültig ist oder in einem akzeptablen Bereich liegt. Wenn sie falsch oder zu alt ist, lehnt sie die Anforderung ab. Eine ausführliche Diskussion finden Sie hier Was nützt ein Client Nonce?



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...