零知识密码证明:为什么在客户端散列密码不是 ZKP?

信息安全 验证 哈希
2021-08-23 19:36:47

设想:

  1. 客户端将其用户名发送u到服务器。
  2. 服务器(username, salt, hashed_password)从其数据库中提取一个username与客户端的用户名匹配的元组uhashed_password是在元组被写入数据库时​​(例如,在用户注册期间)计算的结果hash(salt + password)(其中hash是现代密码散列函数)。
  3. 服务器发送salt给客户端。
  4. 客户端计算并发h := hash(salt + password)送给h服务器。
  5. 服务器比较hhashed_password和授予访问权限,如果哈希匹配。

如果我们假设服务器在用户注册期间没有计算哈希(相反,客户端计算了哈希并将元组发送(username, salt, hashed_password)到服务器以便将其存储在数据库中),为什么这种情况不被认为是零知识密码证明?或者它实际上是一个 ZKP?

据我了解,服务器从未见过实际密码,但可以验证客户端拥有用于创建初始哈希的原始密码。

2个回答

您的协议的主要问题是客户端的第二个答案容易受到重放攻击在登录过程中,攻击者学习uh在以后的恶意登录中被攻击者重用,并导致成功登录。

我建议在此处使用 HMAC 质询-响应身份验证,这意味着客户端从服务器接收质询并返回 HMAC 签名质询(= 响应)。

  • 假设客户端知道密码,客户端能够用它签署消息(对称地使用 HMAC)
  • 从服务器的角度来看,客户端通过对服务器给出的消息进行签名来验证自己

理解这个想法的朴素协议:

1. [C] –––(username)–––> [S]

攻击者:学习用户名(你可能最终想改变它)

2. Server calculates M = (nonce) and stores M

nonce:一堆必须唯一的随机字节,防止重放攻击。为了使其唯一,例如附加时间戳或登录计数器。

2. [C] <––– M ––– [S]

被动攻击者:攻击者每次登录尝试都会学习到不同的 M,即使对于同一用户也是如此。在不知道密码的情况下,攻击者无法对其进行签名。

主动攻击者:操纵 M 无济于事:客户端将签署错误的 M,该 M 稍后将不会被服务器接受。

3. [C] ––– HMAC(M, pw) –––> [S]

被动攻击者:学习签名 HMAC(M,pw)。HMAC 签名不能被重用,因为 M 总是不同的(这就是为什么它必须是唯一的)。

主动攻击者:操纵 M 或 HMAC 签名导致签名无效或与步骤 4 中服务器存储的 M 不匹配。

4. Server examines if the received M equals the stored M and verifies the HMAC signature

这是可能的,因为服务器也知道密码。

这个协议满足了我对维基百科对ZKPP非常松散的定义的解释,因为它是交互式的,并且客户端证明了密码派生数据的知识,而不是密码本身。

一般来说,零知识证明的安全级别是基于迭代过程,我的天真尝试没有涵盖。我建议看看CHAP和/或 SRP。

您的示例完全消除了散列的概念:H(S+P) 成为明文密码,无需任何额外工作即可直接重复使用。