PHP 5.5中的新password_hash API很不错,我想开始在任何地方使用它。鉴于较旧的项目具有较旧的数据库,其中密码存储在md5哈希中,将旧用户密码迁移到新的更安全的API的最佳方法是什么?
除了简单地提示用户在下次登录时重置密码(这对用户来说这是不切实际和恼人的)我已经考虑过使用当前md5哈希作为所有现有用户的password_hash()输入的可能性。为了验证这些用户的密码(在登录期间),我将他们的输入转换为md5哈希,然后将其用于password_verify()。新用户将免于这一额外的步骤。
这是一个值得这样做的方法吗?有没有更好的透明迁移方式,用户不会因为密码重置而烦恼,但我可以立即享受更安全的哈希带来的好处吗?
最重要的是,在使用现有的md5哈希值(易于暴力)和使用password_hash()API来“双重哈希”时,是否有安全优势呢?
答案 0 :(得分:11)
在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/,请务必注意,如果您当前的密码列的长度低于60 ,它需要更改为(或更高)。手册建议长度为255。
您需要更改列的长度并重新开始使用新哈希才能使其生效。否则,MySQL将无声地失败。
答案 1 :(得分:2)
由于它是单向加密,除非您希望登录页面上的用户密码不安全,否则您可以让用户重新输入其密码。另一个选项是在password_hash()
散列密码的基础上用md5()
重新加密所有数据库记录并将这些值存储到数据库中,然后在登录PHP页面上放置password_hash()
你的md5()
,有点像:
password_hash(md5($_POST['password']));
使用第二种方式,您无需让用户重置密码。
答案 2 :(得分: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文档,注意可选的最后一个参数{{ 1}}。