2016-09-03 1 views
2

Ich habe ein Problem, weil ich eine Datenbank mit Benutzern habe und ihre Passwörter mit Django (pbkdf2) gesichert wurden. So ‚123‘ sieht wie folgt aus:Django Passwort in PHP

pbkdf2_sha256$20000$MflWfLXbejfO$tNrjk42YE9ZXkg7IvXY5fikbC+H52Ipd2mf7m0azttk= 

Jetzt muss ich diese Passwörter in PHP-Projekt verwenden, und ich habe keine Ahnung, wie sie zu vergleichen.

+0

Ich stimme gar nicht zu @Sayse - es klingt wie er Django mit PHP ersetzt, so sollte die Antwort nicht "beide laufen" – Fitblip

Antwort

4

pbkdf2_sha256$20000$MflWfLXbejfO$tNrjk42YE9ZXkg7IvXY5fikbC+H52Ipd2mf7m0azttk=

ist dies Lassen brechen. Die $ sind Separatoren:

  • pbkdf2_sh256 bedeutet PBKDF2-SHA256, d.h. hash_pbkf2('sha256', ...)
  • 20000 ist den Iterationszähler
  • MflWfLXbejfO ist das Salz
  • tNrjk42YE9ZXkg7IvXY5fikbC+H52Ipd2mf7m0azttk= ist wahrscheinlich der Hash.

Dies sind alle Informationen, die Sie benötigen, um den Hash von PHP zu validieren. Sie brauchen nur:

  1. hash_pbkdf2() einen neuen Hash aus dem Passwort durch die
  2. hash_equals() Benutzer zur Verfügung gestellt zu erzeugen, den erzeugten Hash mit der gespeicherten

Diese Funktion soll (PHP vergleichen 7+):

/** 
* Verify a Django password (PBKDF2-SHA256) 
* 
* @ref http://stackoverflow.com/a/39311299/2224584 
* @param string $password The password provided by the user 
* @param string $djangoHash The hash stored in the Django app 
* @return bool 
* @throws Exception 
*/ 
function django_password_verify(string $password, string $djangoHash): bool 
{ 
    $pieces = explode('$', $djangoHash); 
    if (count($pieces) !== 4) { 
     throw new Exception("Illegal hash format"); 
    } 
    list($header, $iter, $salt, $hash) = $pieces; 
    // Get the hash algorithm used: 
    if (preg_match('#^pbkdf2_([a-z0-9A-Z]+)$#', $header, $m)) { 
     $algo = $m[1]; 
    } else { 
     throw new Exception(sprintf("Bad header (%s)", $header)); 
    } 
    if (!in_array($algo, hash_algos())) { 
     throw new Exception(sprintf("Illegal hash algorithm (%s)", $algo)); 
    } 

    $calc = hash_pbkdf2(
     $algo, 
     $password, 
     $salt, 
     (int) $iter, 
     32, 
     true 
    ); 
    return hash_equals($calc, base64_decode($hash)); 
} 

Demo: https://3v4l.org/WbTpW

Wenn Sie ältere PHP 5-Unterstützung benötigen, entfernen Sie die string Präfixe und die : bool aus der Funktionsdefinition, damit es mit PHP 5.6 funktioniert. Ich rate nicht zu versuchen, Rückwärtskompatibilität für PHP-Versionen vor 5.6 hinzuzufügen; wenn Sie sich in dieser Situation befinden, you should update your server software instead.

+1

Requisiten für die Verwendung von 'hash_equals' - konstante Zeit Vergleiche sollten * immer * verwendet werden, um Dinge zu vergleichen ein sicherer Weg. Ich denke in diesem Fall, obwohl Sie sicher einen normalen String-Vergleich verwenden können, da die Ausgabe von PBKDF2 nicht von seiner Eingabe erraten werden kann, so gibt es keine Möglichkeit, den Timing-Angriff zu beeinflussen (und sollte daher kein Seitenkanal sein). – Fitblip

+0

Korrekt, es gibt keine praktischen Angriffe auf Passwort Hashfunktionen, die nicht 'hash_equals()'; Ich tue dies aus Gründen der Konsistenz und um gute Gewohnheiten bei Leuten zu etablieren, die auf meine Code-Snippets verweisen. :) –

+1

Welches ist definitiv der Weg, über Dinge zu gehen :). Es tut nie weh, immer einen konstanten Zeitvergleich zu machen (ohne ein paar Zyklen für Hashing), und dann vermasselst du es nie! – Fitblip