【问题标题】:php password_hash, random/static salt and user authphp password_hash、随机/静态盐和用户身份验证
【发布时间】:2014-01-15 13:52:14
【问题描述】:

我一直在阅读有关 php 5.3+ 密码哈希的信息 - 但有几个问题,如果我很愚蠢,请原谅。似乎制作强用户密码哈希的一大抓点是使用随机盐而不是静态盐。如果我检查用户登录,肯定我必须以某种方式使用盐的副本(存储在数据库中)来检查?如果是这样,我是使用安全盐函数(bcrypt salt functions)并将该字符串存储在数据库中(并在每次新登录时重新创建)还是什么?

我有这个:

$options = [
'cost' => 11,
'salt' => mcrypt_create_iv(22, MCRYPT_DEV_URANDOM),

];

当我回显 $options['salt'] 时,我得到了我可能无法存储在数据库中的奇怪字符。我习惯了在数据库中存储随机盐并将其(静态)用于用户登录身份验证的旧(不安全)方法,但动态/随机盐让我有点失望。我错过了什么?随机盐每次都会改变,所以如果我现在存储它,并且用户重新登录哈希会不同,所以数据库密码不会与发布的密码匹配..??

谢谢~

【问题讨论】:

  • 如果数据库暴露给第三方用户,随机加盐没有任何优势。一旦哈希和盐对攻击者可见,随机的就没有用了。你最好使用一个静态的,保存在你的代码中。从统计数据上破解 Web 服务器比数据库更难。
  • 你不使用password_hash()来验证用户密码,只是生成salt并存储密码;您使用password_verify() 来验证存储在数据库中的密码:password_verify() 函数使用盐处理检查
  • 这样的? SetEnv WEBSITE_SALT 232lhsdfjaweufha32i4fv4239tauvkjn 来自:stackoverflow.com/questions/5032341/…
  • @MarkBaker - 我明白这一点,但使用 password_verify 必须提供静态(非随机)盐来检查先前存储的哈希。这就是我问题的症结所在,除非我错过了什么?
  • 单独存放盐是没有意义的。它已经包含在password_hash() 返回的哈希中。只需将整个字符串作为第二个参数传递给password_verify()。顺便说一句:这些函数从 PHP 5.5+ 开始可用。

标签: php hash passwords authentication


【解决方案1】:

似乎制作强用户密码散列的一大抓点是使用随机盐而不是静态盐。

随机盐是 PHP 5.5 的 password_hash() 和用户空间实现 password_compat 的默认行为。

如果我检查用户登录,我肯定必须以某种方式使用盐的副本(存储在数据库中)来检查吗?

盐包含在密码哈希本身中。无需单独存放。

随机盐每次都会改变,所以如果我现在存储它,并且用户重新登录哈希会不同,所以数据库密码不会与发布的密码匹配..??

这是password_verify() 方法的职责。来自 PHP 文档:

请注意,password_hash() 将算法、成本和盐作为返回哈希的一部分返回。因此,验证哈希所需的所有信息都包含在其中。这允许验证函数验证哈希,而无需单独存储盐或算法信息。

编辑:密码验证和随机盐

我想我明白你的困惑来自哪里。希望这将有助于解释密码散列、验证以及随机盐所起的作用。

如果您查看 password_compat (https://github.com/ircmaxell/password_compat/blob/master/lib/password.php) 的来源,您会发现 password_hash()password_verify() 都使用了 PHP 的 crypt() 函数。当您使用password_hash() 创建密码时,您将其存储起来,并且再也不会通过password_hash() 传递该密码。算法、成本和盐都与哈希一起返回。示例:

$options = array('salt' => 'ThisIsTheSaltIProvide.');
$hash = password_hash('password', PASSWORD_DEFAULT, $options);
// $hash = $2y$10$ThisIsTheSaltIProvide.EcCQwybvWB3iNxIv9FwsPJEWhR/ywZ6

我们可以直接使用 crypt 创建相同的哈希,这正是 password_hash() 在幕后所做的。

$hash = crypt('password', '$2y$10$ThisIsTheSaltIProvide.'); 
// $hash = $2y$10$ThisIsTheSaltIProvide.EcCQwybvWB3iNxIv9FwsPJEWhR/ywZ6

哈希包括:

  • 算法信息:$2y$ (BLOWFISH)
  • 成本参数:10
  • 额外的$
  • 盐:ThisIsTheSaltIP提供。

使用该信息,password_verify() 复制哈希,然后将其与持久化哈希进行比较,如下所示:

$existingHash = $2y$10$ThisIsTheSaltIProvide.EcCQwybvWB3iNxIv9FwsPJEWhR/ywZ6
$testHash = crypt('password', '$2y$10$ThisIsTheSaltIProvide.');
// if $existingHash and $testHash match, then the password is good

一种新的、额外的盐永远不会发挥作用。

此外,使用 RANDOM 盐也很重要。如果每个人都使用相同的盐,那么具有相同密码的用户也将具有相同的哈希值。没有人想要那样。

【讨论】:

  • 是的,我知道,但是当用户再次登录时 - 如果我没有盐/特别是如果盐每次都是随机的,我如何根据先前存储的哈希验证输入的密码?这就是我困惑的症结-
  • @FstaRocka 我在答案中添加了相关信息。
  • @FstaRocka 盐存储在password_hash 生成的哈希中。这不是“每次都随机”。
  • @FstaRocka:我在回答中添加了更多信息,试图澄清您关于随机盐和密码比较的问题。
  • 谢谢。我的问题是使用没有选项的密码哈希,即使用每次生成的随机盐。 (在我的原始示例中,您将在我的代码中看到它)。在您的示例中,您设置了一个固定的哈希值,这显然是有意义的。我了解盐和密码之间的关系,但我最初的问题是是否有某种神奇的方式 password_hash 和 password_verify 可以纯粹从算法的角度从不同的盐中嗅出相同的密码..或者我是否需要提供静态盐(如在过去).. 就像将它存储在数据库中。
猜你喜欢
  • 1970-01-01
  • 2014-09-07
  • 2011-05-08
  • 2011-05-06
  • 2015-05-09
  • 2019-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多