客户端密码哈希与纯文本

Client side password hash versus plain text

我正在组装一个 android 客户端(可能在将来 iOS、门户网站等)和 php mysql 服务器。服务器端我目前正在使用 PHPass 库对传入的密码进行散列和加盐处理。

我应该让客户端通过 HTTPS/SSL 发送纯文本密码,还是客户端应该先进行某种形式的哈希处理。例如,每个客户端是否应该简单地对每个传出密码进行 sha1(或其他算法)?

大多数 网站 将通过加密连接 SSL/HTTPS 以明文形式发送密码。可以在客户端对密码进行哈希处理,但优势很小,而且客户端语言 (JavaScrypt) 通常很慢,因此您可以同时计算较少的轮次,这削弱了哈希。在每种情况下,服务器都必须计算哈希值以确保安全。

优势很小,因为如果攻击者可以进行 ManInTheMiddle 攻击,他还可以 modify/remove 执行哈希的脚本 (JS)。只有使用 SSL/HTTPS 的加密连接才能防止 MITM 攻击,因此您无论如何都需要 SSL。

在您使用 app 的情况下,它看起来略有不同。因为用户首先要安装你的软件,没有必要向客户端发送脚本,所以中间人无法修改这个脚本。此外,该应用程序可以相对快速地计算哈希值(如果它可以 运行 本机代码),因此可以在客户端进行足够的轮次。

这就是我要做的:

  1. 为方便起见,通过加密的 SSL/HTTPS 连接发送密码纯文本,并像现在一样计算慢速 BCrypt 哈希服务器端。
  2. 只有当服务器上的负载变得过重时,您才可以将慢速 BCrypt 哈希的计算移至客户端应用程序。仍然使用 HTTPS 发送哈希,然后在服务器上计算一个额外的快速哈希(例如 SHA-256)。这个比较复杂,因为你要单独交换和储存盐。

在客户端散列密码的另一个缺点是,您无法在不更新客户端的情况下更改散列算法或迭代计数。

对于 JavaScript 客户端,这不是问题,但您不能轻易保证您的用户将使用最新版本的本机客户端。

所以我会坚持通过 HTTPS 发送纯密码。

在 HTTP 的早期,有摘要授权作为基本授权的替代。而不是 HTTP header

Authorization: Basic <credentials>

你会用

Authorization: Digest <credentials>

这是一种通过避免以明文形式发送密码来提高安全性的算法。这是在 TLS/SSL 以性能成本为代价的日子里,所以这是一个替代方案。然而,该算法意味着密码必须以明文形式存储在服务器上。因此,您可以选择发送密码明文但在服务器上有哈希,或者以哈希形式发送密码但在服务器上有明文。

不出所料,正如 martinstoeckli 在他的回答中所说,现在 TLS/SSL 广泛且易于实施,因此改用 HTTPS。您可以将密码作为哈希存储在服务器上,但如果它被 MITM 攻击者截获,则不会公开明文密码。