Rolfi: password_verify Passwortabfrage mit Datenbank

Servus,

ich bin gerade am überlegen, welchen Vorteil password_hash für eine Passwortabfrage hat. Ich muss zugeben, ich bin nämlich ein Wenig darüber verwirrt.

Ein Passwort, aber mehrere Hashes: $2y$10$akOaFIUxv9iG584mdXynWOS71IDl9OHDk89nInfX6MsnzfOI5VEPI $2y$10$O5qYpEBJJ3AHLoXIl3/LyONJa8OTkZR0LspxWG2nJnmvPsLyWSQ9a $2y$10$fxOD9pwfUMbLIsgHHdZV8e1IKj1pXqarMS8lWXKJq5QfHhVGQZ10m $2y$10$lxIB3U4hHaIkuifXHq1q7OPMmgKvZY.Jqd1TchXxxZoY8mGt7Taj2 $2y$10$77hysniRyc/r5ORJ0wImXORHDYsajIWUN/rKa.XojKX46CXklNbSi

Ein direkter Vergleich ist in der Datenbank also nicht möglich. Zudem muss ich erst den Hash aus der Datenbank holen um dann mit password_verify zu testen, ob das Passwort stimmt. Danach muss ich eine erneute Datenbankabfrage stellen um die Daten aus der Datenabnk zu holen.

Ist es irgendwie möglich, das password_verify direkt in einer SQL Abfrage zu verwenden? Ich kenne jetzt keine Möglichkeit die erlauben würde, in einer SQL Abfrage das zu benutzen, da der Hash aus der Datenbank ja noch garnicht "geladen" wurde. Das macht die Abfrage ja erst. Ansonsten müsste ich alles in einem Array zwischenspeichern und das Array erst freigeben, wenn das Passwort stimmt. Oder eine zweite Abfrage starten. Ich frage mich aber nach der Performance, direkt zwei Abfragen und einen Haufen mehr Code. Vorher habe ich abgefragt und direkt die Userdaten die man benötigte in eine Session geschrieben.

Außerdem Sicherheit. Ich habe oben 5 mögliche Hashes und sogar weitaus mehr für ein und das selbe Passwort. Abzüglich der ersten 7 Zeichen die immer gleich sind, ist das eine Länge von 53 Zeichen. Und diese Zeichen können öfter das gleiche Passwort repräsentieren, obwohl sie verschieden sind. Ist dann nicht die Wahrscheinlichkeit höher, das Passwort zu knacken, weil man mehr Möglichkeiten hat? sha256 gilt als "unsicher", hat aber 11 Zeichen mehr. Der Hash ist für das Passwort immer eindeutig. Es heißt aber, es könnten Inhalte generiert werden, die den gleichen Fingerabdruck enthalten, also ein Hash theoretisch mehrere Passwörter repräsentieren könnte. Im Gegenzug habe ich aber bei password_hash mehrere Hashes, die das Passwort repräsentieren wobei fraglich ist, ob andere Passwörter bei einer solch hohen Spreizung nicht auch einer dieser vielen Hashes repräsentieren.

Für mich erscheint password_hash unsicherer, andererseits wird empfohlen es vor sha256, md5 etc zu nutzen. Kann mich jemand aufklären?

MfG, Rolfi

  1. Hi,

    Ein direkter Vergleich ist in der Datenbank also nicht möglich.

    Doch, ist er – wenn die Datenbank ebenfalls eine derartige Funktion implementiert hat.

    Außerdem Sicherheit. Ich habe oben 5 mögliche Hashes und sogar weitaus mehr für ein und das selbe Passwort. Abzüglich der ersten 7 Zeichen die immer gleich sind, ist das eine Länge von 53 Zeichen. Und diese Zeichen können öfter das gleiche Passwort repräsentieren, obwohl sie verschieden sind. Ist dann nicht die Wahrscheinlichkeit höher, das Passwort zu knacken, weil man mehr Möglichkeiten hat?

    Nein, man hat nicht „mehr Möglichkeiten” – es liegt ja jeweils nur einer dieser Werte vor für einen Nutzer, und nicht mehrere. Und es geht beim „Passwort knacken“ schließlich nicht darum, den von dir gespeicherten Wert zu „finden“ (der kann als schon gefunden betrachtet werden, wenn deine Datenbank kompromitiert wurde) – sondern den Original-Wert, aus dem dieser Hash gebildet wurde.

    sha256 gilt als "unsicher", hat aber 11 Zeichen mehr.

    Löse dich davon, irgendeine Länge in „Zeichen“ als Maß für Sicherheit zu betrachten.

    Das, was du hier vorliegen hast, enthält neben einem Kennzeichen des verwendeten Hash-Verfahrens (ja, es gibt mehrere zur Auswahl), auch einen „Kostenfaktor“. Die Berechnung des Hashes wird mathematisch aufwendiger gestaltet und damit verzögert – was die Kosten zum Knacken per Brute Force in die Höhe treibt, und damit das ganze sicherer macht. Außerdem enthält es ein zufälliges Salt (und deshalb hast du für ein Passwort nicht nur mehrere Möglichkeiten, sondern „unendlich viele“ – jeder erneute Vorgang der Erzeugung eines Hashes mit password_hash() würde wieder einen anderen Wert ergeben) – so dass selbst wenn ein Passwort von mehreren User verwendet wird, das erfolgreiche „Knacken“ des Passwortes für einen Nutzer immer noch nicht die anderen Accounts kompromitiert.

    Lies mal http://www.phpgangsta.de/schoener-hashen-mit-bcrypt, dann wird dir das ganze vielleicht ein bisschen klarer.

    MfG ChrisB

    --
    Kids these days just don’t get ASCII art any more – it’s all UTF-this and Unicode-that with those youngsters …
  2. Hallo Rolfi,

    Ein Passwort, aber mehrere Hashes

    das liegt in der Natur der Sache. Genau das ist der Sinn von Hashes, dass ein und der selbe Ursprungswert verschiedene Hashes erzeugt. Das erschwert es, auf Grund des Hashes auf den Ursprungswert schließen zu können.

    Zudem muss ich erst den Hash aus der Datenbank holen um dann mit password_verify zu testen, ob das Passwort stimmt. Danach muss ich eine erneute Datenbankabfrage stellen um die Daten aus der Datenabnk zu holen.

    Das verstehe ich nicht, normalerweise hat 1 User 1 Passwort. Du holst also den Hash des Users anhand seines Usernamens aus der DB, vergleichst den Wert mit dem Hash des im Login eingegebenen Passwortes und das stimmt dann oder stimmt nicht. Das benötigt keine "erneute Abfrage".

    Ist es irgendwie möglich, das password_verify direkt in einer SQL Abfrage zu verwenden?

    password_verify() ist eine PHP Funktion, das hat mit SQL nichts zu tun.

    Ansonsten müsste ich alles in einem Array zwischenspeichern und das Array erst freigeben, wenn das Passwort stimmt. Oder eine zweite Abfrage starten.

    Siehe oben! Du machst eine Abfrage und holst Dir den gespeicherten Hash jenes Usernamens, der beim Login eingegeben worden ist. Dann machst Du einen Hash des eingegebenen Passwortes und vergleichst die beiden Werte.

    sha256 gilt als "unsicher", hat aber 11 Zeichen mehr.

    Du kannst das Passwort ja noch salzen, dann ist es schon ziemlich sicher.

    Für mich erscheint password_hash unsicherer

    Im Gegenteil, da ist der Salt-Wert schon dabei! Allerdings funktioniert das nur ab PHP 5 >= 5.5.0!

    Kann mich jemand aufklären?

    Also google mal nach den Begriffen "Hash" und "Salt", um das Grundprinzip zu verstehen. Auf Youtube findest Du auch sehr viele gute Videos, wo die Thematik erklärt und die PHP Verwendung demonstriert wird. Wenn Du eine PHP Version >= 5.5.0 verwendest, dann verwende password_hash, ansonsten nimm hash() mit zB. sha256 plus Salt-Wert!!

    Mit lieben Grüßen

    Melvin Cowznofski

    --
    Melvin Cowznofski What – me worry?
    1. Liebe Mitdenker, liebe Wissende, liebe Neugierige,

      ja!

      Ein Passwort, aber mehrere Hashes

      das liegt in der Natur der Sache. Genau das ist der Sinn von Hashes,

      Nein, das ist der Sinn des automatischen Salts, der mit dem Hash gespeichert wird.

      Zudem muss ich erst den Hash aus der Datenbank holen um dann mit password_verify zu testen, ob das Passwort stimmt. Danach muss ich eine erneute Datenbankabfrage stellen um die Daten aus der Datenabnk zu holen.

      Das stimmt leider, wenn das DBMS keine äquivalente Validierungsfunktion für Hash/Passwort hat. Du kannst dann die Datenabfrage leider nicht kapseln in einer stored Routine. Dazu müsstest Du ggf. die DBMS-eigene crypt()-Funktion verwenden.

      Das verstehe ich nicht, normalerweise hat 1 User 1 Passwort. Du holst also den Hash des Users anhand seines Usernamens aus der DB, vergleichst den Wert mit dem Hash des im Login eingegebenen Passwortes und das stimmt dann oder stimmt nicht. Das benötigt keine "erneute Abfrage".

      Doch, für die Nutzdaten. Und die sind dann nicht kapselbar, da die API entscheidet, ob sie gelesen werden dürfen und nicht das DBMS.

      Ist es irgendwie möglich, das password_verify direkt in einer SQL Abfrage zu verwenden?

      Alles, was außerhalb des DBMS geprüft wird, bricht das Konzept der Kapselung. Das ist aber für Dich nur dann interessant, wenn Du den direkten (Select-)Zugriff auf die Tabellen unterbindest und dafür stored Procedures schreibst. Die ermöglichen dann die Zugriffskontrolle und ein Logging.

      Spirituelle Grüße Euer Robert

      --
      Möge der Forumsgeist wiederbelebt werden!
    2. sha256 gilt als "unsicher", hat aber 11 Zeichen mehr.

      Du kannst das Passwort ja noch salzen, dann ist es schon ziemlich sicher.

      NEIN!

      Hintergrund ist, dass SHAx  1 <= x <= 512 um mindestens den Faktor 1000 schneller ist als der blowfish-Algorithmus.

      Das bedeutet einen enormen Vorteil für den Angreifer der das zum Hash passende Passwort mit einem Wörterbuch oder Brute-Force-Angriff ermitteln will.

      Jörg Reinholz

  3. Tach!

    Ich kenne jetzt keine Möglichkeit die erlauben würde, in einer SQL Abfrage das zu benutzen, da der Hash aus der Datenbank ja noch garnicht "geladen" wurde. Das macht die Abfrage ja erst. Ansonsten müsste ich alles in einem Array zwischenspeichern und das Array erst freigeben, wenn das Passwort stimmt. Oder eine zweite Abfrage starten. Ich frage mich aber nach der Performance, direkt zwei Abfragen und einen Haufen mehr Code. Vorher habe ich abgefragt und direkt die Userdaten die man benötigte in eine Session geschrieben.

    Ich sehe nicht, was daran gegenüber bisher umständlicher sein soll. Du fragst also den User-Datensatz inklusive Passwort-Hash ab und holst mit einem Fetchen die Daten in ein Array. Dann lässt du das Passwort vergleichen und schreibst bei Erfolg die Daten aus dem Array oder es selbst in die Session. Früher hast du dasselbe gemacht, nur ohne Passwort-Vergleichen-Lassen. Aber ohne Codevergleich kann man da schlecht was dazu sagen oder vorschlagen.

    dedlfix.