And*_*ord 11 php hash bcrypt symfony php-password-hash
我正在开发一个用于用户身份验证的现有Symfony2.8 Web应用程序项目FOSUserBundle.
除了Web前端,用户还可以使用不同的智能手机客户端使用REST API连接到Web应用程序.因此,在直接登录Web应用程序和连接REST API的原因时,用户都需要进行身份验证.
直到其中一个最新FOSUserBundle更新bcrypt密码哈希和用于salt存储在数据库中的地方.
使用REST API进行连接时,会将salt传输到客户端,以使用相同的salt对密码进行本地哈希处理.散列密码将发送回Web应用程序进行身份验证.
我知道发送散列密码而不是纯文本不会增加(很多)额外的安全性,因为只能使用HTTPS进行通信.然而,这是客户端工作的方式:他们需要salt来生成哈希密码.我可以在将来更新客户端,但现在这只是工作方式.
问题:
他们的方式FOSUserBundle哈希密码已经改变:因为不考虑手动指定盐而是让PHP自动生成盐(在PHP 7中甚至不能手动设置盐),手册盐不再受支持.
直接登录Web应用程序时没有问题,但由于REST客户端仍需要salt,因此此更新会中断REST连接.
有没有办法结合这两种方法?让PHP自动创建盐,提取并将此盐发送给客户端?
据我所知,salt与哈希存储在同一个字符串中:
但是,只需从哈希字符串中复制21个char盐并将这些发送到客户端就不起作用了.似乎这21个字符足以测试/验证密码,但不能重新创建哈希.它是否正确?
那么,是否有任何解决方案使用PHP password_hash而不设置盐,并同时了解用过的盐?
编辑1:
回答@RiggsFolly问题:MD5在任何时候都没有使用过.这是不正确的,bcryp/ password_hash不会两次创建相同的哈希.如果密码和盐都相同,它会这样做:
$s = 'password';
$salt = 'salt5678901234567890123456789012';
$options['salt'] = $salt;
$h1 = password_hash($s,PASSWORD_BCRYPT,$options);
$h2 = password_hash($s,PASSWORD_BCRYPT,$options);
echo $h1 . PHP_EOL;
echo $h2 . PHP_EOL;
Run Code Online (Sandbox Code Playgroud)
结果:
$2y$10$salt56789012345678901uTWNlUnhu5K/xBrtKYTo7oDy8zMr/csu
$2y$10$salt56789012345678901uTWNlUnhu5K/xBrtKYTo7oDy8zMr/csu
Run Code Online (Sandbox Code Playgroud)
password_hash如果未指定salt,将为相同的密码创建新哈希.这是因为,盐将随机创建,而不是每次调用时产生不同的盐.
编辑2:
正如编辑1中所见,使用具有32个字符的盐将导致字符串仅包含盐的前21个字符.但是,这个salt-prefix不能用于重新创建相同的哈希值,因为它太短而不能被接受.
但是,如果前缀填充0,它似乎工作:
$s = 'password';
$salt = 'salt5678901234567890123456789012';
$salt_prefix = 'salt5678901234567890100000000000';
$h1 = password_hash($s, PASSWORD_BCRYPT, array('salt' => $salt));
$h2 = password_hash($s, PASSWORD_BCRYPT, array('salt' => $salt_prefix));
echo $h1 . PHP_EOL;
echo $h2 . PHP_EOL;
Run Code Online (Sandbox Code Playgroud)
所以解决方案可能是:
FOSUserBundle使用password_hash创建哈希而无需手动指定salt.任何人都可以确认,这是一个真正的解决方案,而不仅仅是一些巧合吗?
您似乎误解了密码散列和盐的工作原理。
盐永远不会发送给客户。它仅在创建密码时生成(或手动指定)一次。其目的是随机化哈希函数的输出,以便当数据库落入坏人之手时,无法通过将输出与彩虹表进行比较来获取用户密码。
当用户使用密码登录时,密码会以未散列的方式从客户端发送到服务器(但通常通过 https)。然后,密码比较函数获取存储的哈希+密码,从中获取盐,将盐附加到用户输入,计算哈希,然后将其与数据库中的哈希进行比较。
也许您正在进行的项目对盐的实施很糟糕。事实上,不鼓励使用手动加盐的原因之一是为了防止类似的情况发生。
所以解决方案可能是:
让FOSUserBundle 使用password_hash 创建哈希值,而无需手动指定salt。
从结果字符串中提取盐并用 0 填充到 32 个字符的长度
将这个盐传递给客户端
任何人都可以确认这是一个真正的解决方案而不仅仅是巧合吗?
这不是一个好的解决方案。唯一的好方法是确保以正确的方式实现密码哈希,这样您就不必多次生成盐。