为什么每次请求都使用身份验证令牌而不是用户名/密码?

信息安全 密码 验证 Web应用程序 饼干
2021-09-03 12:19:54

https://stackoverflow.com/a/477578/14731的作者推荐:

不要在您的数据库中存储持久登录 COOKIE(令牌),只存储它的哈希值![...] 在存储持久登录令牌时使用强加盐哈希(bcrypt / phpass)。

我的印象是登录 cookie 有两个目的:

  1. UX 好处:不要求用户每次请求登录一次
  2. 性能优势:不需要为每个请求运行慢速算法(如 bcrypt)

似乎作者正在使第二点无效,这让我想知道:为什么要使用身份验证令牌呢?httpOnly与其将用户名/密码映射到随机选择的身份验证令牌,不如简单地使用securecookie 传递每个请求的用户名/密码?

假设我们接受作者的建议并在每个请求中使用 bcrypt,那么使用身份验证令牌而不是用户名/密码有什么好处?

1个回答

当您使用“身份验证令牌”时,客户端对该令牌的简单表示将授予访问权限(只要该令牌被服务器视为有效)。如果您将令牌“按原样”存储在服务器的数据库中,那么可以瞥见您的数据库的攻击者将立即了解所有令牌,从而允许他以仍然存在有效令牌的所有用户的名义发送请求在数据库中。这不好。因此,建议仅存储身份验证令牌的哈希值。

关于 bcrypt用于身份验证令牌的建议是错误的。Bcrypt 与所有专用于密码散列的函数一样,旨在用于密码密码很弱;他们很容易受到字典攻击。为了解决它们固有的弱点,密码散列函数必须加盐(以防止并行攻击和预先计算的表)并且还必须非常慢(如果内部迭代则通过大量)。这使得密码散列函数变得昂贵所以你不想使用密码散列函数,除非你需要它,例如散列密码。

身份验证令牌不是密码;它是由计算机生成和记忆的随机值,过程中不涉及任何人脑。因此,如果您正确生成了令牌(至少 128 位,从加密安全的 PRNG获得),那么就不需要盐或迭代;只需使用普通的哈希函数(即使是 MD5 也可以)。这样会更有效率。

至于对每个请求使用随机身份验证令牌而不是登录名+密码,主要原因有两个:

  1. 性能:如上所述,可以使用简单的哈希安全地验证身份验证令牌,这将比繁重的 bcrypt 调用更有效。您希望在真正有用的时候保留宝贵的 CPU 周期,尤其是在将 bcrypt 应用于实际的人工管理密码时。

  2. 客户端存储:身份验证令牌将作为 cookie 值存储在客户端。如果登录名和密码随每个请求一起发回,则它们将作为 cookie 存储在客户端上。当他们的密码被写入文件时,人们会感到紧张——并且这种存储(从安全角度来看)不等同于身份验证令牌的存储,因为人类用户有(坏)习惯重复使用他们的密码多次系统,而身份验证令牌本质上是特定于服务器的。