将 PBKDF2 馈送到 SRP 验证器创建

信息安全 密码 哈希 协议 srp
2021-08-30 02:17:04

有一款老游戏只使用 UDP 进行通信,我想在游戏中添加密码验证,以方便经验值和排名之类的事情。为此,我决定使用现有游戏协议的扩展通过 UDP 通信的 SRP-6a 实现,我最终在游戏客户端使用cocagne/csrp,通过游戏服务器和mozilla/身份验证服务器端的node-srp,稍作修改以产生与csrp兼容HAMK的后续响应。

到目前为止,它运行得相当好,但是我不喜欢验证器是如何存储在静止状态的,因为在计算x输入的过程中,在变成验证器之前,它似乎只被散列一次v,见这里我建议我们更改这个库函数以满足我们的需要(因为它相当小并且已经在树中)并使用沿 PBKDF2 行的东西。然而,我从另一位开发人员那里得到了(可以理解的)关于触摸这种性质的代码、善意等等的回击。

相反,建议用户的密码本身可能会经过 PBKDF2 散列,然后作为密码传递给验证程序创建和用户质询功能。这样,我们就不必修改 csrp 库本身的任何代码。这是一种有效的方法吗?或者,如果我们这样做,是否还有另一个陷阱在等着诱捕我们?

对于它的价值,完整的协议文档在这里,所以如果我正在制造任何其他类型的混乱,很高兴知道。

1个回答

SRP 中的密码实际上是(可能)低熵的共享秘密它可以是人类用户理解的“密码”,也可以是从密码确定性派生的任何内容。在您的情况下,是的,使用密码散列函数(例如 PBKDF2)是一种有效的方法。它有以下警告:

  • PBKDF2 与 bcrypt 和其他良好的密码散列函数一样,需要salt盐很重要。没有盐,攻击者可以在很大程度上优化攻击;也就是说,他只需要为一个用户支付 PBKDF2 步骤的费用(如果他有几个存储的哈希值供多个用户破解)。这里的要点是客户端和服务器必须为给定用户使用相同的盐,因此客户端必须以某种方式知道该盐。但是盐仍然必须特定于每个用户(并且每当用户更改密码时也会更改),因此您不能简单地在客户端代码中对其进行硬编码。

    因此,您需要将每个用户的 salt 存储在服务器上,并将其作为初始身份验证步骤传送给客户端。在 SRP 中,客户端首先发送包含用户名 ( I ) 和不依赖于密码 ( A ) 的值的消息。服务器使用特定于用户的盐 ( s ) 和另一条消息 ( B ) 进行响应。应该在该服务器到客户端消息中发送 PBKDF2 所需的额外盐。

    或者,您可以将 SRP 中的散列步骤替换为 PBKDF2,但这涉及修改协议实现库,这可能不是一个好主意。添加额外的 PBKDF2 步骤更简单,也更安全。

    重用与 SRP 指定的盐(协议规范中称为s的盐)相同的盐是很诱人的。虽然这在这里看起来是加密安全的(两种盐的用法有点“分离”,它们之间的所有 PBKDF2),但这种事情被认为是一个微妙的问题,而且,再一次,有一个额外的、独立的盐是安全、谨慎的方法。

  • PBKDF2 采用多次迭代来减缓攻击者的速度。但它也会减慢普通用户的速度,因此您无法将迭代次数提高到您希望的程度。考虑到所涉及计算机的负载和计算能力,以及用户耐心的限制,您应该设置尽可能高的值。

    在与 SRP 集成的情况下,与任何其他PAKE协议一样,密码散列的主要成本在客户端。因此,适当的迭代计数取决于客户端计算机如果您有多个客户端,那么您必须调整到仍然应该能够连接的最不强大的计算机。这一点对于使用 JavaScript 的基于 Web 的客户端尤其重要,因为 JavaScript 对于原始计算非常微弱,严重限制了您可以容忍的迭代次数。在您的情况下,客户端的代码使用 C 库,因此您可以拥有一些客户端肌肉,但是由于您正在使用“旧游戏”,因此您必须考虑客户端可能是“旧机器”,可能是“长辈 机器”。有一些变态仍然在护理一些 i486 计算机。

  • 您可以考虑使用 bcrypt 代替 PBKDF2;bcrypt可以说对使用 GPU 的攻击者更强大。