Authentication 如何保存密码散列,以便匹配已散列的密码?

Authentication 如何保存密码散列,以便匹配已散列的密码?,authentication,cakephp,cookies,cakephp-3.x,Authentication,Cakephp,Cookies,Cakephp 3.x,我正在实现一个“记住我”的特性(CakePHP3),它将用户名和散列密码存储在cookie中。我的问题是,我没有成功地将cookie中的哈希密码与数据库中的哈希密码进行匹配 我使用DefaultPasswordHasher生成数据库哈希和cookie哈希。我起初以为这些会匹配,但事实似乎并非如此 我的第二个想法是DefaultPasswordHasher将有一个函数,可以验证两个哈希来自同一个密码,但其check()函数使用纯文本密码: 网上类似的问题似乎都适用于旧版本的蛋糕,或者都没有定论 从

我正在实现一个“记住我”的特性(CakePHP3),它将用户名和散列密码存储在cookie中。我的问题是,我没有成功地将cookie中的哈希密码与数据库中的哈希密码进行匹配

我使用DefaultPasswordHasher生成数据库哈希和cookie哈希。我起初以为这些会匹配,但事实似乎并非如此

我的第二个想法是DefaultPasswordHasher将有一个函数,可以验证两个哈希来自同一个密码,但其check()函数使用纯文本密码:

网上类似的问题似乎都适用于旧版本的蛋糕,或者都没有定论

从用户实体:

protected function _setPassword($password)
{
  if (strlen($password) > 0) {
    return (new DefaultPasswordHasher)->hash($password);
  }
}
从UsersController login()函数

从AppController initialize()函数:

// Load logged in user
$loggedInUserID = $this->Auth->user('id');

// If not logged in try cookie
if( !$loggedInUserID && $cookie = $this->Cookie->read('cookie_name') ) {
    error_log("Attempting to log in from cookie. Username: ".$cookie['username']);
    $user = $this->Users->find('all', [
        'conditions' => [
            'username' => $cookie['username'],
            'password' => $cookie['password'],
            'is_deleted' => 0
        ]
    ])
    ->first();

    // If a user was found, try to login
    if ($user) {
        if($this->Auth->login($user)) {
            error_log("Successfully logged in from cookie. Username: ".$cookie['username']);
            $loggedInUserID = $this->Auth->user('id');
        } else {
            error_log("Couldn't log in from cookie. Username: ".$cookie['username']);
            $this->redirect('/users/logout'); // destroy session & cookie
        }
    }
}
(为了清楚起见,我保留了临时错误日志消息。)

cookie似乎保存正确,但其哈希与数据库不匹配,这意味着永远找不到与cookie匹配的用户


两个哈希值应该匹配的问题是什么?或者我应该使用一个函数来匹配这两个哈希吗?

首先,您可能想看看新的身份验证插件,它附带了一个现成的cookie身份验证程序

这就是说,您的前提是错误的,两个哈希不匹配的事实是出于设计和正确的行为,没有方法可以匹配它们

您应该做的是在cookie中存储一个唯一标识符,比如用户名,以及从第二个凭据构建的哈希,当您尝试通过cookie数据登录时,需要能够再次构建该哈希。比如说用户名+散列密码的散列,散列密码,因为您需要再次使用该精确值来重新创建普通值,以便将其与存储在cookie中的散列进行比较,即您不能(也不应该)使用普通密码,因为它在后续请求中不再可用

然后,当使用cookie数据登录时,使用唯一标识符(用户名)查询用户,并通过密码哈希器的
check()
方法将普通值(用户名+哈希密码)与cookie哈希进行比较

对于给定的示例,可能类似于以下内容(免责声明,这是未经测试的示例代码):

$user=$this->Users->get($this->Auth->user('id');
$savedUser=[
“用户名”=>$user->username,
'token'=>(新的DefaultPasswordHasher())->哈希(
$user->username.:'.$user->password
),
];
// ...
它查询并使用当前登录的用户,因此您必须在调用
$this->Auth->identify()
后执行此操作

/。。。
$user=$this->Users
->查找()
->在哪里([
'username'=>$cookie['username'],
“是否已删除”=>0,
])
->第一个();
如果($user){
$plain=$user->username.:'。$user->password;
if((新的DefaultPasswordHasher())->检查($plain,$cookie['token'])){
//哈希匹配,用户登录
$user=$user->toArray();
取消设置($user['password']);//但不要将密码放入会话中
$this->Auth->setUser($user);
}否则{
//哈希不匹配,请执行其他操作
}
}
注意使用了
setUser()
,CakePHP 3.x
AuthComponent
中没有
login()
方法,
login()
方法来自CakePHP 2.x!理想情况下,您还可以在自定义身份验证对象和
Auth.afterIdentify
事件的事件处理程序中处理所有这些,并将逻辑排除在控制器之外

另见


散列通常是咸的,否则使用相同密码的用户的密码散列很容易识别;这是一个安全弱点。但是,我认为cookie哈希不匹配,因为这不是它的目的。我认为cookie散列可以防止浏览器攻击者从用户cookie中检索密码。也许客户端应该简单地将散列值转换回密码字符串,并将其发送到
check()
方法?您可以根据您的配置查看哪个方法提供对“当前密码”的干式检查。如果你还没有使用新的auth插件。非常感谢你的快速回答!我有一种感觉,这是沿着这些路线,但我不太明白流程。我认为我发现的建议代码的唯一问题是使用+而不是点来连接。我认为$user->username应该是一个数组元素:$user['username']Oops,是的,它应该是一个点。对象访问应该是正常的,除非您禁用水合作用,否则数组访问也可以在实体实现
\ArrayAccess
时工作@西蒙
// Load logged in user
$loggedInUserID = $this->Auth->user('id');

// If not logged in try cookie
if( !$loggedInUserID && $cookie = $this->Cookie->read('cookie_name') ) {
    error_log("Attempting to log in from cookie. Username: ".$cookie['username']);
    $user = $this->Users->find('all', [
        'conditions' => [
            'username' => $cookie['username'],
            'password' => $cookie['password'],
            'is_deleted' => 0
        ]
    ])
    ->first();

    // If a user was found, try to login
    if ($user) {
        if($this->Auth->login($user)) {
            error_log("Successfully logged in from cookie. Username: ".$cookie['username']);
            $loggedInUserID = $this->Auth->user('id');
        } else {
            error_log("Couldn't log in from cookie. Username: ".$cookie['username']);
            $this->redirect('/users/logout'); // destroy session & cookie
        }
    }
}