PHP Mysql安全密码

Far*_*ame 2 php mysql security encryption

我知道这个问题很多,但是现在(2016年4月),为我的用户安全存储密码的首选方法是什么?我的数据不是超敏感的(它只是一个没有个人或财务细节的游戏,但拥有安全密码仍然很好).

今晚我已经阅读了大量的教程和问题,但目前还不清楚.我只想要一个相当简单易懂但相当安全的方法来获取创建的密码,将其存储在我的数据库中然后检索它.我已经尝试了几种方法,它们都工作正常,但后来有人说它不安全或者事情已经发生了变化.很高兴看到几个明确的功能来加密和解密密码.

编辑 - 澄清为什么新答案比stackoverflow上的先前答案更好.该语言已使用password_hash()和password_verify()进行了更新,极大地简化并改善了这种情况.以前的答案提供了手动解决方案,节省盐,使用不同的算法等.现在都不需要.

Sco*_*ski 7

我知道这个问题很多,但是现在(2016年4月),为我的用户安全存储密码的首选方法是什么?我的数据不是超敏感的(它只是一个没有个人或财务细节的游戏,但拥有安全密码仍然很好).

我保留了James Patterson在他的回答中所链接的博客文章.虽然只有两个月的时间,但已经有了大规模的更新,但是由于其他几种语言的缓慢运动而受到阻碍.我可以为您提供PHP的即时更新答案.

我将以这种格式回答:

  1. 你今天应该做些什么(即标准反应)以及为什么.
  2. 你今年晚些时候应该做些什么.
  3. 你应该在未来几年做些什么.

如何在2016年安全存储密码

正如在PHP密码存储部分的当前迭代中提到的博客文章,您希望通过PHP的内置密码API促进bcrypt.这个API很简单,但是你需要记住一些问题:

使用bcrypt哈希密码

$hash = password_hash($userPassword, PASSWORD_DEFAULT);
Run Code Online (Sandbox Code Playgroud)

使用bcrypt验证密码

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现在是首选算法,原因有很多:

  • 出色的GPU抗性(在抵制密码破解方面非常重要)
  • 经过专家多年研究 - 这是保守的选择
  • 在低内存配置中,它比scrypt更安全.

为什么 bcrypt?

你应该注意bcrypt有两个已知的弱点:

  1. Bcrypt 在72个字符后截断.
  2. Bcrypt \0字节后截断.

通常,人们在尝试解决第一个问题时会遇到第二个问题.现在一个好的止损解决方案是:

今日推荐:Bcrypt-SHA-384(带base64编码)

/**
 * 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(或更新版本).

使用libsodium在PHP中使用Argon2i哈希密码

$hash = \Sodium\crypto_pwhash_str(
    $password,
    \Sodium\CRYPTO_PWHASH_OPSLIMIT_INTERACTIVE,
    \Sodium\CRYPTO_PWHASH_MEMLIMIT_INTERACTIVE
);
Run Code Online (Sandbox Code Playgroud)

使用libsodium在PHP中使用Argon2i验证密码

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.

因此,长期解决方案可能只是:

将来使用Argon2i哈希密码

$hash = password_hash($userPassword, PASSWORD_DEFAULT);
Run Code Online (Sandbox Code Playgroud)

将来使用Argon2i验证密码

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更长,所以只要使用那些,除非你有令人信服的理由做更多.


Dav*_*yly 5

你不存储密码,你存储单向哈希.即使您使用加密,也不要存储密码!

原因是,如果数据库遭到破坏,您将打开密码并可供所有人查看.即使它们是加密的,你需要做的就是破解密钥和POW,每个密码都被解锁.这非常非常糟糕.

另一方面,哈希是单向加密.根据哈希测试密码,响应为真或假(授权或未授权).你永远不会直接存储密码,所以如果你的数据泄漏,你必须单独破解每个密码 - 并且使用盐渍哈希和良好的哈希算法,祝你好运.

幸运的是,PHP的最新版本大大简化了该过程.password_hash()password_verify()从中消除所有的不确定性.

  • 是的,曾经有很多不同的方式,然后更新版本的PHP使用这两个本机函数解决了这个问题.如今,你真正需要知道的! (2认同)