2016-09-03 3 views
2

У меня проблема, потому что у меня есть база данных с пользователями, и их пароли были защищены Django (pbkdf2). Так «123» выглядит следующим образом:Django password в PHP

pbkdf2_sha256$20000$MflWfLXbejfO$tNrjk42YE9ZXkg7IvXY5fikbC+H52Ipd2mf7m0azttk= 

Теперь мне нужно использовать эти пароли в проекте PHP и я не имею ни малейшего представления, как их сравнивать.

+0

Я категорически не согласен с @Sayse - похоже, что он заменяет django на PHP, поэтому ответ не должен быть «запущен» – Fitblip

ответ

4

pbkdf2_sha256$20000$MflWfLXbejfO$tNrjk42YE9ZXkg7IvXY5fikbC+H52Ipd2mf7m0azttk=

Давайте разберем это вниз. $ сепараторы:

  • pbkdf2_sh256 означает PBKDF2-SHA256, т.е. hash_pbkf2('sha256', ...)
  • 20000 является счетчик цикла
  • MflWfLXbejfO это соль
  • tNrjk42YE9ZXkg7IvXY5fikbC+H52Ipd2mf7m0azttk=, скорее всего, хэш.

Это вся информация, необходимая для проверки хеша из PHP. Вам просто нужно:

  1. hash_pbkdf2() создать новый хэш от пароля, предоставленного пользователем
  2. hash_equals() сравнить сгенерированный хеш с сохраненным одним

Эта функция должна работать (PHP 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)); 
} 

Демо: https://3v4l.org/WbTpW

Если вам нужна устаревшая поддержка PHP 5, удаление префиксов string и : bool из определения функции заставит его работать на PHP 5.6. Я не рекомендую добавлять обратную совместимость для версий PHP раньше 5.6; если вы окажетесь в этой ситуации, you should update your server software instead.

+1

Реквизиты для использования 'hash_equals' - постоянные сравнения времени должны всегда использоваться * для сравнения вещей в безопасным способом. Я думаю, что в этом случае вы можете безопасно использовать обычное сравнение строк, поскольку выход PBKDF2 не может быть угадан с его ввода, поэтому нет никакого способа повлиять на синхронизацию (и поэтому не должен быть побочным каналом). – Fitblip

+0

Правильно, нет никаких практических атак на функции хэширования паролей, которые не используют 'hash_equals()'; Я делаю это для согласованности и устанавливаю хорошие привычки у людей, которые ссылаются на мои фрагменты кода. :) –

+1

Это, безусловно, способ обойти вещи :). Никогда не повредит постоянное сравнение времени (без нескольких циклов для хэширования), а затем вы никогда не завинчиваете его! – Fitblip