【问题标题】:password_hash and password_verify returns falsepassword_hash 和 password_verify 返回 false
【发布时间】:2014-01-10 00:57:53
【问题描述】:

我有以下密码:

123

现在我散列它并返回以下键:

$2y$10$rSq.2M7Ikc.QPhVtYlp1Nu8HI.Eq5fUgVWn25J

现在我尝试使用以下方法验证相同的密钥:

return password_verify(123, $2y$10$rSq.2M7Ikc.QPhVtYlp1Nu8HI.Eq5fUgVWn25J);

然而这会返回 false。

谁能告诉我为什么?

更新

这是我的完整代码:

<?php
/**
 * Created by JetBrains PhpStorm.
 * User: Marc
 * Date: 14-12-13
 * Time: 13:56
 * To change this template use File | Settings | File Templates.
 */
class Security {
    /**
     * @param $string
     * @return mixed
     */
    public function encrypt($string) {
        return password_hash($string, PASSWORD_DEFAULT);
    }

    /**
     * @param $string
     * @param $hash
     * @return mixed
     */
    public function validate($string, $hash) {
        return password_verify($string, $hash);
    }
}

    $hash = $this->db->template("SELECT password FROM User WHERE username = '".$username."'", READ_FROM_QUERY)['password'];
$validate =  $this->getSecurity()->validate($password, $hash);

我尝试插入以下字符串:

Helloworld

然而$validate = false;

密码已返回$2y$10$VbicsFaGN9d3ggQTNYIto.Bp6x/rbjpsBe2kneEhJ9oP2KdPsZ7hy

如果我尝试重新散列它,它会返回相同的值,所以它们必须彼此相等,那么为什么它返回 false?!??!

也返回 false

$validate =  $this->getSecurity()->validate((string)$password, (string)$hash);

【问题讨论】:

  • 尝试将密码作为字符串传递给 password_verify()
  • 您是如何生成该哈希的? password_verify() 仅使用 password_hash() 散列密码运行?!?
  • 好的,让我试着改写我的问题
  • @MarkBaker 你能更具体地看看我的更新吗?
  • @MarkBaker 将它们作为字符串还是 int 传递并不重要,因为无论如何它都会被转换为字符串。即使在没有任何引号的情况下传递 Helloworld 也可以正常工作(尽管会产生未定义的变量警告)。

标签: php passwords password-encryption


【解决方案1】:

对于您的第一个示例,密码为 123,问题是您正在截断哈希。

$settings = array('cost' => 10, 'salt' => 'rSq.2M7Ikc.QPhVtYlp1Nu');                                        
echo password_hash('123', PASSWORD_BCRYPT, $settings);
// $2y$10$rSq.2M7Ikc.QPhVtYlp1Nu8HI.Eq5fUgVWn25J/WWUma/RrNWKFay // What is echoed
// $2y$10$rSq.2M7Ikc.QPhVtYlp1Nu8HI.Eq5fUgVWn25J                // Your hash

我假设您的数据库列的最大长度为 45 个字符,这就是它截断它的原因。

对于第二个字符串,问题在于您将密码转换为小写。

// Uppercase 'H'
$settings = array('cost' => 10, 'salt' => 'VbicsFaGN9d3ggQTNYIto.');
echo password_hash('Helloworld', PASSWORD_BCRYPT, $settings);
// $2y$10$VbicsFaGN9d3ggQTNYIto.qFAer7kUmKmcy6y9RCNzaaKD7fJraba

// Lowercase 'h'
$settings = array('cost' => 10, 'salt' => 'VbicsFaGN9d3ggQTNYIto.');
echo password_hash('helloworld', PASSWORD_BCRYPT, $settings);
// $2y$10$VbicsFaGN9d3ggQTNYIto.Bp6x/rbjpsBe2kneEhJ9oP2KdPsZ7hy

因此,当您尝试使用 Helloworld 进行验证时,它将返回 false,因为哈希是针对 helloworld 的。

您确实需要更加小心,因为这两个都是非常粗心的错误。请注意,您永远不应该将密码转换为特定大小写(大写或小写),因为这会大大削弱密码。

【讨论】:

  • 这可能是相关的,来自php.net/crypt --- "基于标准 DES 的 crypt() 返回盐作为输出的前两个字符。它也只使用第一个str 的八个字符,因此以相同八个字符开头的较长字符串将生成相同的结果(当使用相同的盐时)。"
  • @Fred-ii- 有趣...但是 password_hash 现在只使用 bcrypt(注意字符串以 $2y$ 开头)。
  • 我认为可能是相同或相似的情况。
  • @Fred-ii- 嗯,这是在讨论被散列的字符串,而不是散列本身。因此,无论哪种方式,它都不会截断散列。例如,微软多年来一直在默默地使用 16 个字符的 Hotmail 截断密码。如果您有更长的密码,他们只会使用前 16 个字符,因此您可以为超过 16 个字符的所有内容输入随机字符并进入。现在他们实际上强制您使用 16 个字符的密码或更少。哪个疯子认为这是处理安全问题的最佳方式?我认为他们的操作系统也是如此。
  • 我听说 Hotmail 以纯文本形式存储密码。我不记得我在哪里读到的,但我几乎想相信它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多