如何正确应用客户端密码哈希?

How to correctly apply client side hashing of passwords?

我正在寻找一种既定的安全机制来应用客户端密码散列以及服务器端密码散列。客户端是 Web 应用程序或移动应用程序。客户端和服务器之间的通信使用 HTTPS。服务器应使用 bcrypt 或类似的安全密码哈希算法。

现在,我不想将未加密的密码从客户端发送到服务器,以防止对用户的内部攻击。我想确保我们的 none 管理员能够获得原始密码,因为——众所周知——大多数人在多个网站上重复使用他们的密码或使用密码方案来派生密码很容易记住。

此外,我想在身份验证协议中实施额外的两因素安全层,利用存储在客户端上的秘密来进一步加强整体安全性。

是否有任何已发布和验证的机制可用于这种情况?

编辑 在我的场景中,邪恶的管理员无法控制应用程序的代码。进行身份验证并提供敏感数据的服务器是 REST 服务器。应用程序代码由不同的服务器(对于 Web 应用程序)或通过 AppStore(对于移动应用程序)提供。而且我也在考虑攻击者对连接 HTTPS 服务器和应用程序服务器的内部网段只有只读访问权限的场景。在大多数现实世界的设置中,SSL 终止是在专用服务器上完成的。

网站 相比,您使用 app 的场景非常适合客户端散列。该应用程序已经包含用于计算哈希的代码,并且代码不能是 intercepted/altered,因为 JavaScript 就是这种情况。更重要的是,您可以将服务器从 CPU 密集计算中解放出来。

这些是注册的必要步骤:

  1. 在客户端,使用具有成本因子的慢散列函数计算密码的散列值。合适的算法是 BCrypt、PBKDF2 或 SCrypt。大多数库会自行生成随机盐并将其包含在生成的哈希值中。
  2. 将客户端哈希发送到服务器(您已经提到了 SSL 连接)。
  3. 在服务器端,再次计算发送的客户端哈希值的哈希值。这次你不需要盐,你可以使用像 SHA-256 这样的快速算法。这是安全的,因为 client-hash 已经很强大 "password",不可能从 server-hash 中伪造 client-hash。
  4. 从客户端哈希中提取盐、成本因子和算法等参数。
  5. 将服务器哈希和参数(salt,...)存储在数据库中。

登录步骤如下:

  1. 客户端必须请求参数(盐,...),存储在服务器的数据库中。
  2. 客户端使用与注册相同的参数计算密码的哈希。
  3. 将客户端哈希发送到服务器。
  4. 服务器再次使用快速算法对客户端哈希进行哈希处理,并将其与数据库中存储的哈希进行比较。

这比单独的服务器端哈希稍微复杂一些,因为您必须注意单独存储参数(salt,...)。