2013-09-19 3 views
8

Новый API password_hash в PHP 5.5 хорош, и я бы хотел начать использовать его везде. Учитывая старый проект с более старой базой данных, в которой пароли хранятся в хэшах md5, каков наилучший способ переноса старых паролей пользователей на новый, более безопасный API?Преобразование хэшей паролей md5 в PHP 5.5 password_hash()

Помимо простого запроса пользователям сбросить свой пароль при следующем входе в систему (это непрактично и раздражает пользователей). Я подумал о возможности использования текущего хеша хд5 в качестве входного пароля для пароля для всех моих существующих пользователей. Чтобы проверить пароли для этих пользователей (во время входа в систему), я бы конвертировал их вход в хеш-файл md5, а затем использовал его для password_verify(). Новые пользователи будут избавлены от этого дополнительного шага.

Действительно ли это стоит того? Есть ли лучшие способы прозрачной миграции, в которых пользователи не навязываются сбрасыванием пароля, но я могу сразу воспользоваться преимуществами более безопасного хэширования?

Самое главное, есть ли преимущество безопасности при использовании существующих хешей md5 (которые подвержены грубой силе) и использование API password_hash() для «двойного хэша»?

+2

Обычно вы можете просто подождать, пока пользователь не войдет в систему в следующий раз, я написал ответ на тот же вопрос здесь [Перемещение старых паролей на новый алгоритм хэширования?] (Http://stackoverflow.com/a/14402451/575765). Поскольку MD5 очень слаб для хэширования паролей, вы можете рассмотреть вопрос о сохранении хэширования BCrypt вашего хэша MD5 'password_hash ($ existingMD5Hash)' и перенести его в 'password_hash ($ password)' при следующем входе в систему. – martinstoeckli

+0

См. Также раздел [PHP-хэш-система Openwall] (http://www.openwall.com/phpass/) (PHPass). Он переносится и затвердевает от ряда распространенных атак на пароли пользователей. Парень, который написал рамки (SolarDesigner) тот же самый парень, который написал [John The Ripper] (http://www.openwall.com/john/) и сидит в качестве судьи в [хэширования паролей конкуренции] (HTTP://password-hashing.net/). Поэтому он знает кое-что об атаках на пароли. – jww

ответ

9

В вашем login.php (?) Вы конвертируете старые пароли из MD5 в bcrypt и заменяете старый хэш MD5 в базе данных новым.

Псевдо код:

$password = $_POST["password"]; 

if (substr($pwInDatabase, 0, 1) == "$") 
{ 
    // Password already converted, verify using password_verify 
} 
else 
{ 
    // User still using the old MD5, update it! 

    if (md5($password) == $pwInDatabase) 
    { 
     $db->storePw(password_hash($password)); 
    } 
} 

Двойной хэширования не увеличит безопасность Bcrypt, поскольку Bcrypt itsef является функцией хеширования односторонняя.

Nota: MD5 производит длину строки в 32 символов, в то время как password_hash() это минимум 60.

Прочитайте руководство:

Если и когда вы решите используйте password_hash() или пакет совместимости (если PHP < 5.5) https://github.com/ircmaxell/password_compat/, важно отметить, что если длина текущего столбца пароля меньше, чем n 60, его нужно будет изменить на это (или выше). В руководстве предлагается длина 255.

Вам потребуется ALTER length вашей колонки и начать с нового хэша, чтобы он вступил в силу. В противном случае MySQL будет терпеть неудачу.

+1

Я бы просто добавил к этому, что из того, что я читал с тех пор, и что сказал martinstoeckli выше - двойное хеширование на самом деле полезно для существующих паролей MD5, поскольку оно улучшает безопасность слабых MD5-хэшей. Итак: password_hash ($ existingMD5Hash). Затем, когда пользователь входит в систему, я могу сделать то, что вы здесь объяснили ... – Aron

2

Поскольку это одностороннее шифрование, если вы не хотите, чтобы пароли пользователей на вашей странице входа в систему не были безопасными, вы можете заставить пользователей повторно вводить свои пароли. Другой вариант заключается в reencrypt всех записей базы данных с password_hash() поверх их md5() хэшированных паролей и хранить эти значения в базу данных, то на странице Войти PHP поставить password_hash() вокруг md5(), вроде:

password_hash(md5($_POST['password'])); 

Используя второй способ, вы не должны перезагружать свои пароли.

0

Существует очень специфический прецедент, который еще не упоминался здесь, и это уже когда вы сделали первый шаг и начали использовать функцию crypt, но все еще используете алгоритм MD5.

В этом случае ваш пароль хеширования при изменении регистрации/пароля будет выглядеть следующим образом:

$pass_hash = crypt($pass, '$1$salthere'); 
// store $pass_hash in database 

И тогда вы бы сравнение с:

if(hash_equals($pass_hash_from_db, crypt($user_input, '$1$salthere'))) 
{ 
    // user logged in 
} 

Прелесть этого перехода является то, что базы данных уже будет в состоянии готово использовать password_verify.

Регистрация/изменение пароля станет:

$pass_hash = password_hash($pass); 
// store $pass_hash in database 

А вы бы заменить сравнение с:

if(password_verify($user_input, $pass_hash_from_db)) 
{ 
    // user logged in 
} 

Это просто работать из коробки, и обновить пароли всех пользовательских на следующий пароль изменение. Но нам не нужно ждать и делать то, что @Fabian сделал в своем ответе здесь.

Здесь нам нужно только изменить логин:

if(password_verify($user_input, $pass_hash_from_db)) 
{ 
    // user logged in 
    if(password_needs_rehash($pass_hash_from_db, PASSWORD_DEFAULT)) 
    { 
    $pass_hash = password_hash($user_input); 
    // store $pass_hash in database 
    } 
} 

Это будет служить дополнительным преимуществом обновления паролей пользователя, как только новый алгоритм пароля будет PHP по умолчанию один. Вам на самом деле ничего не нужно делать.

Если вы хотите использовать дополнительные параметры для функции хеширования пароля (например, изменения «стоимости»), вы должны смотреть на password_hash и password_needs_rehash документации, обратите внимание на опциональный последний параметр $options.

Смежные вопросы