【问题标题】:PHP password_hash function value isn't same for each string每个字符串的 PHP password_hash 函数值不同
【发布时间】:2015-02-20 10:05:54
【问题描述】:

我正在尝试使用 password_hash() PHP 函数对用户密码进行哈希处理。但是,它的功能是工作哈希,而不是恒定的。

<?php 
    echo password_hash('a',PASSWORD_BCRYPT,array(
            'cost' => 12
         ));
?>

第四次测试结果

1. $2y$12$SRmipqM7AsYkx3Xc8QGHNex69rGXeVyWGTYrh9T8sh1cP3UrdjfQi
2. $2y$12$zx.GUgtcake3wMfl3/YXXeG1.8mmHKyRruL3nWj8OmA.RbEYqeW6u
3. $2y$12$XQtmFplcehkgWLbGrOUsNOlXDU/NGrwZlt3HM88hLbUHXhjXNF4km
4. $2y$12$q9/OSZdDJw7af4Hw4MGlHeY7UMtWr9/Cj0nj/N6PaoilNoUBePt7O

【问题讨论】:

  • 你期待什么?它会是恒定的吗?
  • 每次使用 password_hash() 时不带 salt 时,它会生成一个随机盐,这意味着您的密码不会是固定的。因为password_hash() 生成散列并且散列基本上是盐+散列password_verify() 方法需要密码和散列密码密码[参数1]将使用散列密码中的盐进行散列,如果它等于它返回true,否则它会失败:-)

标签: php password-hash php-password-hash


【解决方案1】:

正如一些人建议使用 MD5,不要将其用于密码哈希。

现在回答你的问题how to check a password matches

Password_Hash() 是生成一个密码散列,它会用它创建一个随机盐,这个散列将在散列时使用。 你的最终结果是:salt+hash,然而你可以在它的选项中使用这个方法给它一个salt,但让我们让它自己做。

Password_Verify() 使用一个参数作为密码,一个参数作为散列密码。 正如我之前所说,哈希密码是 salt+hash 这是有道理的 Password_Verify() 只需要这些,而不是额外的称为 salt

所以Password_Verify() 发生的事情是它取出盐并将Password_Hash() 与该盐一起使用。 然后检查接收到的哈希是否等于给定的哈希。 如果匹配则为真,否则为假。

Password_Hash() Doc

Password_Verify() Doc


2018 年 4 月 18 日更新(日-月-年)

警告

PHP 7.0.0 起,salt 选项已弃用

现在最好只使用默认生成的盐。

More information about Salting - SO Answer below by Veve

Why not to use MD5 for Password Hashing - PHP FaQ Answer

Why not to use MD5 for Password Hashing - SO Answer by: Silverlightfox

【讨论】:

  • 没问题,记住,如果有帮助不要忘记接受答案:-) 我也肯定会说:只要使用给定的方法。生成的盐非常好,使用password_hash()password_verify()
  • 我真的很了解password_hash()password_verify()。谢谢@MikeM。我接受你的回答太迟了。
【解决方案2】:

如果您想使用password_hash() 并获取常量哈希(不确定复数...),请在使用时添加盐。 (但不要,请参阅下面的警告

explained in the doc一样,如果你不这样做,每次使用该函数时都会随机生成salt,因此生成的哈希不会是恒定的。

<?php 
    echo password_hash('a',PASSWORD_BCRYPT,array(
            'salt' => $salt_defined_for_the_user,
            'cost' => 12,
         ));
?>

关于你应该使用的盐,这里有一个很好的解释wmfrancia提取的from here

腌制

密码在散列前应始终加盐。盐渍添加随机 密码的字符串,因此相似的密码在 数据库。但是,如果盐不是每个用户唯一的(即:您使用 硬编码盐)比你几乎使你的盐一文不值。 因为一旦攻击者找出一个密码盐,他就有了盐 为他们所有人。

当您创建盐时,请确保它对于密码是唯一的 加盐,然后将完成的哈希和盐存储在您的数据库中。什么 这样做是为了让攻击者必须单独 在他们获得访问权限之前破解每个盐和哈希。这意味着很多 攻击者需要更多的工作和时间。


注意:您不应该尝试使用自己的盐获取常量哈希

我只是在这里回应您愿意拥有恒定哈希值,但正如 cmets 中的 halfermartinstoeckli 所说,并且在官方文档中也有说明,

注意 强烈建议您不要为此函数生成自己的盐。它将自动创建一个安全的盐 如果您不指定一个,则为您提供。

你真的应该创建你自己的盐,函数会尝试它的 最好创建一个安全和随机的。当您存储特定于用户的 salt 如您的示例所示,您的操作与 password_hash() 相同 反正。它在哈希值中包含盐,因此函数 password_verify() 可以从那里获取它

Mike M.the use of password_verify() instead in his answer 的详细描述。

【讨论】:

  • $salt_defined _for_the_user 只需要最少 22 个字符。 :P :)
  • 除非你知道自己在做什么,否则我建议使用该函数的默认 salt 功能。
  • 你真的应该创建你自己的salt,这个函数会尽力创建一个安全和随机的salt。如示例所示,当您存储用户特定的盐时,您的操作与 password_hash() 一样。它在哈希值中包含盐,因此函数password_verify() 可以从那里获取它。
  • 我并不是说他必须创建盐,我只是在回答他关于获取恒定哈希的问题。我会将您的警告添加到我的答案中。
  • Veve 检查我的答案我详细解释了,在 Password_Hash() 文档中以 CAUTION 开头的 Note 下的第一个示例下也有警告
【解决方案3】:

我认为您对无论您尝试多少次都会产生相同哈希值的旧方法感到困惑。

例如 MD5 () 将始终为相同的密码五个相同的哈希值..

Password_hash 始终为您提供不同的字符串,因为每次运行它时它都包含不同的盐。

当您从数据库中检索哈希密码时(例如,基于用户提供的电子邮件) Password_verify 将一起读取 salt+pass 的整个字符串,将使用作为 salt 的第一个字符,并将此 salt 与用户提供的普通密码一起使用来加密它。

然后它将结果与从数据库中提取的剩余 salt+hash 进行比较(现在剩余的应该是 hash.. 没有 salt)。

我希望这有助于你理解为什么你总是得到不同的字符串,你对相同的密码使用密码哈希。

【讨论】:

    猜你喜欢
    • 2016-01-11
    • 1970-01-01
    • 2017-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多