客户端密码哈希

信息安全 哈希 爪哇 客户端 bcrypt pbkdf2
2021-08-16 21:00:25

编辑:更新以更加强调目标 - 让用户安心,而不是加强安全性。

在阅读了这里关于客户端密码散列的一些讨论之后,我仍然想知道在特定情况下使用它是否可以。

具体来说,我想让客户端 - 一个 Java 程序 - 使用 PBKDF2 之类的东西对他们的密码进行哈希处理,使用他们的电子邮件地址和特定于应用程序的常量字节块的组合作为盐。这个想法是散列可用于身份验证,但希望不会受到逆向工程攻击(以发现文字密码),而不是在服务器数据受到破坏时使用暴力破解。

目标:

客户端散列是为了让用户放心,服务器永远不会收到他们的文字密码,即使有保证在存储中对其进行散列也是如此。另一个好处(或者可能是一个责任?)是迭代的​​ PBKDF2 或类似的散列成本取决于客户端。

环境特征是:

  1. 所有客户端-服务器通信都是加密的。
  2. 不允许重播消息。IE。从客户端发送的哈希不能被窃听者有效地用作密码。
  3. 对于在短时间内多次登录失败的尝试,临时禁止和黑名单 IP 是可能的。这可能是每个用户帐户或系统范围内的。

关注点:

  1. “避免设计自制的身份验证方案。”
  2. salt 对于每个用户都是确定性的,即使生成的哈希将特定于该应用程序,因为将(相同的)额外字节放入 salt 中。这很糟糕吗?
  3. 服务器端的身份验证不会有任何明显的延迟,也不会产生散列成本。这是否会增加分布式暴力验证攻击的脆弱性?
  4. 流氓客户可以为他们自己的账户提供一个弱散列。其实,也不必太担心这个。
  5. 服务器是否应该在存储之前重新散列客户端散列?

想法?

4个回答

客户端的散列并不能解决密码散列旨在解决的主要问题——如果攻击者获得对散列密码数据库的访问权会发生什么。由于客户端发送的(散列)密码按原样存储在数据库中,因此此类攻击者可以通过按原样向服务器发送来自数据库的散列密码来冒充所有用户。

另一方面,客户端的散列很好,因为它可以确保用户服务器不知道密码 - 如果用户对多个服务使用相同的密码(就像大多数用户一样),这很有用。

一个可能的解决方案是在客户端和服务器端进行散列。您仍然可以将繁重的 PBKDF2 操作卸载到客户端,并在服务器端执行单个哈希操作(在客户端 PBKDF2 哈希密码上)。客户端中的 PBKDF2 将防止字典攻击,服务器端的单个哈希操作将防止使用来自被盗数据库的哈希密码。

很少有时间值得客户端散列。一种这样的情况是当哈希过程计算密集时, PBKDF2可能就是这种情况。

解决您的疑虑:

  1. 还要避免在互联网上找到关于密码学的未经验证的建议。(免责声明:我不是布鲁斯·施奈尔。)
  2. 确定性盐不是问题——盐的唯一真正要求是它对每个用户都是唯一的。salt 的真正目的是防止在数据库受损的情况下,对一个密码的暴力破解变成对所有密码的暴力破解。即使您要在散列密码旁边的数据库中存储随机盐,您仍然可以达到此目标,前提是每个用户的密码不同。
  3. 正如我上面提到的,PBKDF2 很好,因为您可以任意决定哈希的计算难度。您可以选择一个c,这样现代硬件上的单个散列需要几秒钟——有效地消除了 API 级别暴力攻击的风险。(当然,您的客户可能不会在登录时享受如此长的延迟。)
  4. 用户可以选择简单的密码——他们只会伤害自己。如果您想消除这种风险,您可以让服务器第一次生成哈希,前提是密码通过加密通道。
  5. 是的,您还需要对这些进行独特的加盐。如果发生数据库泄露,您需要确保攻击者不会获得允许他/她直接以您系统上的任何用户身份进行身份验证的信息。这里需要注意的一个问题是,您不希望您的服务器端散列像您的客户端散列那样是计算密集型的。如果你的服务器端散列花费太多精力,你就会让自己面临 CPU 耗尽的拒绝服务攻击向量——攻击者只是通过 Tor 发送空密码验证尝试,你的服务器必须在它知道它们之前尝试散列密码。欺诈性的,最终让您不堪重负的服务器..

如果您在客户端散列密码,无论结果是密码,所以您不会获得任何真正的安全性。任何会泄露纯文本密码的黑客或信息泄露都会显示散列密码,这是真正的密码。

这不应该与零知识身份验证方案混淆,其中消息交换证明客户端知道真正的密码,而不实际传输它。

似乎您正在尝试发明自己的加密协议。从您的方法的描述来看,您似乎没有以安全方式执行此操作的背景。我强烈建议使用现有协议而不是创建自己的协议。

首先,尚不清楚您认为自己正在规避哪种威胁模型。你引用了一种叫做“逆向工程攻击”的东西,它没有真正的定义或意义。

其次,您似乎缺乏对盐的用途和最佳实践的理解。盐不需要保密。您可以(并且应该)为每个新的身份验证令牌从 CSPRNG 生成唯一的盐,而不是从电子邮件地址之类的东西(可能会更改)。固定的特定于应用程序的盐有时被称为“辣椒”,我不知道有任何支持或鼓励使用它们的密码学文献。

第三,PBKDF2 没问题,但认真地使用 BCryptBCrypt 就是为此而设计的,并且被广泛使用。良好的 BCrypt 实现将为您处理盐生成和工作因子校准/自动检测。你必须自己实现这些东西才能使用 PBKDF2,而且你几乎不可避免地会犯错误。

第四,对于您似乎正在尝试做的事情,有一种现有的方法。可以使用SRP执行零知识认证。用户的密码永远不会通过网络传输,中间的人无法嗅出任何有用的信息来验证自己的身份。但是,它显然很难正确实现,并且没有多少现有的库可以这样做,这应该可以让您了解问题的实际难度。

长话短说:不要发明自己的加密货币。使用广泛实施并经受住时间考验的解决方案和协议。