Far*_*ame 2 php mysql security encryption
我知道这个问题很多,但是现在(2016年4月),为我的用户安全存储密码的首选方法是什么?我的数据不是超敏感的(它只是一个没有个人或财务细节的游戏,但拥有安全密码仍然很好).
今晚我已经阅读了大量的教程和问题,但目前还不清楚.我只想要一个相当简单易懂但相当安全的方法来获取创建的密码,将其存储在我的数据库中然后检索它.我已经尝试了几种方法,它们都工作正常,但后来有人说它不安全或者事情已经发生了变化.很高兴看到几个明确的功能来加密和解密密码.
编辑 - 澄清为什么新答案比stackoverflow上的先前答案更好.该语言已使用password_hash()和password_verify()进行了更新,极大地简化并改善了这种情况.以前的答案提供了手动解决方案,节省盐,使用不同的算法等.现在都不需要.
我知道这个问题很多,但是现在(2016年4月),为我的用户安全存储密码的首选方法是什么?我的数据不是超敏感的(它只是一个没有个人或财务细节的游戏,但拥有安全密码仍然很好).
我保留了James Patterson在他的回答中所链接的博客文章.虽然只有两个月的时间,但已经有了大规模的更新,但是由于其他几种语言的缓慢运动而受到阻碍.我可以为您提供PHP的即时更新答案.
我将以这种格式回答:
正如在PHP密码存储部分的当前迭代中提到的博客文章,您希望通过PHP的内置密码API促进bcrypt.这个API很简单,但是你需要记住一些问题:
$hash = password_hash($userPassword, PASSWORD_DEFAULT);
Run Code Online (Sandbox Code Playgroud)
if (password_verify($userPassword, $hash)) {
// Login successful.
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
// Recalculate a new password_hash() and overwrite the one we stored previously
}
}
Run Code Online (Sandbox Code Playgroud)
Bcrypt现在是首选算法,原因有很多:
你应该注意bcrypt有两个已知的弱点:
通常,人们在尝试解决第一个问题时会遇到第二个问题.现在一个好的止损解决方案是:
/**
* Bcrypt-SHA-384 Verification
*
* @ref http://stackoverflow.com/a/36638120/2224584
* @param string $plaintext
* @param string $Hash
* @return bool
*/
function bcrypt_sha384_verify(string $plaintext, string $hash): bool
{
$prehash = \base64_encode(
\hash('sha384', $plaintext, true)
);
return \password_verify($prehash, $hash);
}
/**
* Creates a Bcrypt-SHA-384 hash
*
* @ref http://stackoverflow.com/a/36638120/2224584
* @param string $plaintext
* @param int $cost
* @return string
*/
function bcrypt_sha384_hash(string $plaintext, int $cost = 12): string
{
$prehash = \base64_encode(
\hash('sha384', $plaintext, true)
);
return \password_hash(
$prehash,
PASSWORD_BCRYPT,
['cost' => $cost]
);
}
Run Code Online (Sandbox Code Playgroud)
2016年如何安全存储用户密码涵盖了具体推理.
今年晚些时候,您可能会考虑转而使用密码哈希竞赛的获胜者Argon2.(这不是强制性的; bcrypt仍然相当不错.但在未来几年中,Argon2将成为推荐的算法,除非对它进行任何新的攻击.)
事实上,你现在可以使用它.你只需要安装libsodium 1.0.9和libsodium-php 1.0.3(或更新版本).
$hash = \Sodium\crypto_pwhash_str(
$password,
\Sodium\CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
\Sodium\CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
);
Run Code Online (Sandbox Code Playgroud)
if (\Sodium\crypto_pwhash_str_verify($hash, $password)) {
// Login successful
}
Run Code Online (Sandbox Code Playgroud)
如果您使用的是Halite 2.0.0或更高版本,则PasswordAPI使用Argon2i,然后使用经过身份验证的加密来加密哈希值.(这比"胡椒"更好.)
我将很快提出一个RFC,将Argon2i作为一种可能的算法添加到密码散列API中.如果它在PHP 7.1的功能冻结时及时被接受,我们可能会看到早在PHP 7.3(它应该在2018年发布)中就是默认的Argon2i.
因此,长期解决方案可能只是:
$hash = password_hash($userPassword, PASSWORD_DEFAULT);
Run Code Online (Sandbox Code Playgroud)
if (password_verify($userPassword, $hash)) {
// Login successful.
if (password_needs_rehash($hash, PASSWORD_DEFAULT)) {
// Recalculate a new password_hash() and overwrite the one we stored previously
}
}
Run Code Online (Sandbox Code Playgroud)
有很多事情可以做,以提高密码的安全散列现在,但是从长远来看密码哈希API将兜了一圈和懒惰的答案今天将再次成为明天的最佳实践的答案.
TL; DR:password_hash()并且password_verify()将比bcrypt更长,所以只要使用那些,除非你有令人信服的理由做更多.
你不存储密码,你存储单向哈希.即使您使用加密,也不要存储密码!
原因是,如果数据库遭到破坏,您将打开密码并可供所有人查看.即使它们是加密的,你需要做的就是破解密钥和POW,每个密码都被解锁.这非常非常糟糕.
另一方面,哈希是单向加密.根据哈希测试密码,响应为真或假(授权或未授权).你永远不会直接存储密码,所以如果你的数据泄漏,你必须单独破解每个密码 - 并且使用盐渍哈希和良好的哈希算法,祝你好运.
幸运的是,PHP的最新版本大大简化了该过程.password_hash()并password_verify()从中消除所有的不确定性.
| 归档时间: |
|
| 查看次数: |
3941 次 |
| 最近记录: |