【发布时间】:2018-02-27 21:52:57
【问题描述】:
我已将重置密码问题追溯到 DatabaseTokenRepository 中的哈希方法。
当它比较两个令牌散列(一个来自用户的重置请求和一个来自数据库)时,无论如何它都会失败。我已经尝试从数据库中简单地复制粘贴并以这种方式比较两个字符串,但它仍然返回 false。
我正在使用 Laravel 5.4
用户的令牌(来自重置电子邮件)
"$2y$10$xAnDTr6/G41sAROp4h76hOhx7c4Ily4eYBtFc1J4voCgwIRhq9Mge"
数据库令牌
"$2y$10$xAnDTr6/G41sAROp4h76hOhx7c4Ily4eYBtFc1J4voCgwIRhq9Mge"
哈希函数的返回仍然是false。
来自DatabaseTokenRepository
的代码public function exists(CanResetPasswordContract $user, $token)
{
$record = (array) $this->getTable()->where(
'email', $user->getEmailForPasswordReset()
)->first();
//dump($token);
//dump($record['token']);
//dd($this->hasher->check($token, $record['token']));
return $record &&
! $this->tokenExpired($record['created_at']) &&
$this->hasher->check($token, $record['token']);
}
编辑:
使用 hash_equals($token, $record['token']); 返回 true,但这不是解决方案(因为这是源文件,更新这些文件会破坏我的功能)
【问题讨论】:
-
当你说用户的令牌是你提供的。真的吗?这已经散列了。
-
它应该是散列的,这是 Laravel 处理密码重置的方式。您在 GET 路由中使用散列字符串,例如 '/password/reset/{token}',然后它会验证它是否是数据库中的相同散列并允许您更改密码 - 但是因为它使用 password_verify 比较散列它失败(因为它需要一个非散列值)。这就是我想在不更改源文件的情况下规避的问题。 @apokryfos
-
不,不是。
$hasher->check在内部使用password_verify,它接受未散列的值作为第一个参数并将其与散列进行比较。如果您将实际的哈希值传输给用户,那么对任何内容进行哈希处理也毫无意义。 -
嗯,我使用的是 Laravel 自带的开箱即用的解决方案?所以我看不出它不应该被散列,当它在电子邮件中向我射击时?当您只需要将所述散列与数据库中的散列进行比较时,传输散列确实有意义。哈希本身根本不包含任何数据,它只包含 40 个随机字母和一个哈希键,如 DatabaseTokenRepository 中所定义。
-
我发现了问题,这是我的愚蠢和盲目的看法。我进一步研究了您所说的内容,它不起作用的原因是因为我在发送电子邮件时使用了已经散列的令牌,而不是通过构造将未散列的令牌发送到电子邮件 - 这导致 password_verify 失败.我调查了你提到的奇怪的事情,这似乎是因为它 hash_hmac 是密钥,然后它 bcrypts 那个哈希。然而问题解决了,感谢您的洞察力。谢谢!