记住我令牌中的哈希用户名和密码?

信息安全 饼干
2021-09-09 10:14:27

MVC 框架 Symfony 在创建记住我的 cookie 时使用以下方法:

/**
 * Generates a hash for the cookie to ensure it is not being tempered with.
 *
 * @param string $class
 * @param string $username The username
 * @param int    $expires  The Unix timestamp when the cookie expires
 * @param string $password The encoded password
 *
 * @return string
 */
protected function generateCookieHash($class, $username, $expires, $password)
{
    return hash_hmac('sha256', $class.$username.$expires.$password, $this->getKey());
}

所以他们使用用户类的字符串,后跟用户名,然后是时间戳,然后是用户密码。它被一个永不改变的密钥加盐,并且对整个系统的所有用户都是平等的。

现在这是我的问题:为什么将密码放在cookie中?虽然它是经过哈希处理的加盐密码(使用另一个盐,每个用户都是唯一的),但这不是不必要的风险吗?

还是我在这里偏执?

此外,使用该哈希,似乎唯一独特的是过期时间戳。似乎可以复制一些旧的 cookie 并创建一个新的 cookie 来进行重放攻击,对吧?

更新

生成的 Cookie 是 base64 编码的,其解码后的内容是:

Somenamespace\YourApp\YourUserClass:MjQ2NjM=:1501576079:74fbfcddcc66c2a11586bf4e39e68ddb459afa3a3fa6684e93d03fc393ee1141

第一个元素是用户类。第二个参数应该是 base64 编码的用户名,但这是我得到的,所以我猜它是用户 ID。我也会尝试找出它是如何工作的。第三个参数是“过期”时间戳,所以你甚至不必猜测。第四个参数表示cookie hash。

3个回答

这种机制使得当用户更改密码时,所有“记住我”会话都将失效。

该机制在安全性方面的两个关键特征是:

  • 如果攻击者设法以某种方式访问​​ cookie,则无法从 cookie 中的散列中确定密码。
  • 攻击者无法使用其他数据重新创建“remember-me”cookie 以获取另一台机器的访问权限。

乍一看,因为 cookie 包含密码的哈希

Somenamespace\YourApp\YourUserClass:MjQ2NjM=:1501576079:74fbfcddcc66c2a11586bf4e39e68ddb459afa3a3fa6684e93d03fc393ee1141

看起来攻击者可以暴力破解或“密码猜测”来确定测试密码是否生成相同的哈希(上面的第 4 个参数)。然而,由于这是一个密钥哈希(在这种情况下是 HMAC),攻击者将没有密钥来对 cookie 值执行这种攻击。

关于第二点,出于同样的原因,攻击者也很难做到这一点。由于哈希的密钥是未知的,因此即使用户 ID、类别和到期时间已知,攻击者也几乎不可能重新创建“记住我”cookie。

...现在这是我的问题:为什么将密码放在 cookie 中?虽然它是经过哈希处理的加盐密码(使用另一个盐,每个用户都是唯一的),但这不是不必要的风险吗?

风险评估是根据具体情况进行的,因此如果没有进一步详细说明其使用地点,我们不能说它是否可以接受(这不是 SE 的问题)

正如所指出的,为什么当前密码(以任何形式)是散列令牌的一部分,用于添加熵,并将密码与令牌联系起来。

因此,用于不同密码的类似令牌将不起作用。这使系统能够在密码更改时“自动注销”任何人,而无需明确注销并跟踪所有“记住我”令牌。

密码本身应该是散列形式(可能是加盐的),因为我们永远不应该存储未散列的密码。

还是我在这里偏执?

是的,但这是一件坏事吗?……声音在说什么??

此外,使用该哈希,似乎唯一独特的是过期时间戳。似乎可以复制一些旧的 cookie 并创建一个新的 cookie 来进行重放攻击,对吧?

嗯,不。作为攻击者,您需要用户名和密码来重新创建哈希以获得“有效”攻击令牌。如果攻击者拥有用户名和密码,您将遇到更大的问题。

我可以看到在生成的哈希中添加密码参数的唯一原因是,当用户更改密码时,其他计算机中的其他持久会话将自动终止。
这也是强制使用新密码重新验证的好习惯。