it-swarm.com.de

Wie funktioniert das Speichern von Hash-Passwörtern?

Wird in normalen Netzwerkanwendungen, die Kennwort-Hashing verwenden, 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, wenn 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?

27
Allahjane

Zumindest 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 Datenbank gibt alle Zugriffe.

In den meisten Fällen Das gesamte Hashing wird 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), kann der Großteil des Hashing-Prozesses auf der Clientseite ausgeführt werden, es muss jedoch noch eine endgültige Hash-Berechnung auf dem Server durchgeführt werden.

39
Thomas Pornin

Wie das Anmeldekennwort-Hashing funktionieren soll

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

Wird in normalen Netzwerkanwendungen, die Kennwort-Hashing verwenden, 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?

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 Passwort wie folgt:

public void RegisterAccount(string username, string password, string email)
{
     if (!Database.EmailExists(email) && !Database.UsernameExists(username))
     {
         Database.AddNewUser(username, Hash.GenerateHash(password), email);
     }
}

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

Angenommen, Sie geben als Passwort "Hack mich bitte nicht" ein. bcrypt verwandelt das in $2a$08$BOHyNdXAVkWOUgPG/hvsjew7ZpngqJIgueY6m76xd4y3UllXUZLBy oder eine andere Variante, die auf dem Salz basiert. Die Datenbank sieht jetzt so aus:

+--------------+--------------------------------------------------------------+--------------------+
|    user      |    password                                                  |       email        |
+--------------+--------------------------------------------------------------+--------------------+
| markbuffalo  | $2a$08$BOHyNdXAVkWOUgPG/hvsjew7ZpngqJIgueY6m76xd4y3UllXUZLBy |   [email protected] |
+--------------+--------------------------------------------------------------+--------------------+

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 nicht einfach den Hash übergeben, um sich anzumelden?

Sie können 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 per Code geschehen kann:

public void Login(string username, string password)
{
    if (Database.LoginMatches(username, password) ||
        Database.LoginMatches(username, Hash.ValidateHash(password)))
    {
        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. Rufen Sie die vorherige Tabelle auf. Eine der folgenden Anmeldungen funktioniert ordnungsgemäß:

  1. Login("markbuffalo", "$2a$08$BOHyNdXAVkWOUgPG/hvsjew7ZpngqJIgueY6m76xd4y3UllXUZLBy");
  2. Login("markbuffalo", @"don't hack me please");

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


Was ist der richtige Ansatz zur Hash-Validierung?

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

24
Mark Buffalo

Zu deiner ersten Frage :

Das 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 deiner zweiten Frage :

Der Server erwartet eine Passworteingabe: X. Der Angreifer findet irgendwie heraus h(X). Wenn er dann diesen Hash-Wert zur Authentifizierung eingeben würde, würde die Hash-Funktion erneut für h(x) ausgeführt, sodass er nicht einsteigen könnte, da h(x) nicht mit h(h(x)).

3
Rápli András

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

       Client      <----- Secure link ----->     Server
Cleartext password     Encrypted password    Hashed password
  1. Der Client hat das Klartext-Passwort.
  2. Client verschlüsselt Passwort (über TLS)
  3. Server empfängt verschlüsseltes Passwort, entschlüsselt es (via TLS)
  4. Der Server hascht das Kennwort mit demselben Salt, das in der Datenbank für diesen Benutzer gespeichert ist
  5. Der Server vergleicht den berechneten Hash mit dem gespeicherten Hash.

Schutz:

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

Das Problem besteht nun darin, dass 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 könnte ). Die traditionellen Entscheidungen (für PPP) waren:

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

  • CHAP : Verwenden Sie ein Challenge-Response-Protokoll und senden Sie eine Hash-Version des Passworts (kombiniert mit der Challenge und einer ID) über den Link Server zum Speichern des Klartextes der Passwörter

Ersteres schützt also vor Diebstahl von Kennwortdatenbanken, nicht jedoch vor Abhören, während sich bei letzterem die Situation umkehrt.

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, mit dem ein nicht umkehrbarer "Hash" des Kennworts an gesendet werden kann ein Server, der auch einen "Hash" des Passworts speichert: SRP und allgemeiner "augmented PAKE "Protokolle.

1
jcaron

Ein Angriff, der auf dem 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?

0
Ken