客户端密码散列
Clientside password hashing
我和我的一个朋友正在讨论我们是否应该在将 web 应用程序的用户密码发送到我们的服务器之前对其进行预散列。
我知道有多个问题已经处理了这个主题,但它们都是关于将它安全地传输到服务器的。我们的想法与传输安全性无关(我们使用 SSL),我们希望对客户端进行哈希处理以防止 "real" 密码到达我们的服务器。
这个想法是在 Twitter 宣布他们的错误导致密码以明文形式打印到日志文件时产生的。
我们目前正在讨论这个概念是否有意义,以及如果我们使用 SHA512 对其进行哈希处理,它会如何影响密码的安全性(就 Bruteforce 而言)。
TL;DR:
我们想在客户端对密码进行哈希处理,以防止我们的服务器以明文形式获取密码(我们使用 SSL 进行传输)。
这有意义吗?
哪种算法最适合用于哈希?
经过哈希处理的密码将在服务器端再次使用 bCrypt 进行哈希处理。
否!
密码学的第一条规则:不要自己发明它,否则你会犯可怕的错误。
这不是针对您个人的,目前为止不是:即使是一流的专家在精心设计新系统时也会犯错误。这就是为什么在任何东西成为标准之前,他们会多次对彼此的工作进行同行评审。由于在此类同行评审期间发现的问题,此类专家针对此类标准提出的许多提案都被重新制定。那么,为什么我们其他人不能进行凡人设计:没有人足够优秀来进行同行评审,因为专家不会碰它。
对密码客户端进行哈希处理
哈希客户端真的很糟糕,因为哈希变成了密码,现在你把它明文存储在服务器上。
如何设置密码
- 只存储哈希密码(暗示:将密码发送到服务器,只是不存储它)
- 使用盐并将其与密码一起存储(未加密)。 salt 本质上是一个随机字符串,在对其进行哈希处理之前将其连接到密码(以存储它并验证它)
使用慢散列。使用快速散列是一个常见且致命的错误,即使在使用盐时也是如此。人们知道的大多数散列函数,如 SHA-256、SHA-3 等,都是快速散列,完全不适合散列短的、可预测的项目,如密码,因为它们可以在极短的时间内被逆转。
多慢:尽可能慢。慢散列的例子:
bcrypt,PBKDF-2(本质上是大量轮的a
快速散列使其变慢)
根据您的编程环境,有预制例程,请使用它们!
参考:
虽然 @swa66 概述了如何安全地管理密码,但请注意 是 可以考虑客户端密码散列的有效方案,所以不要盲目关注"best practice",先尝试了解一下。
假设我有一个存储用户数据的标准 Web 应用程序。在我的威胁模型中,我什至不希望我自己的用户必须信任我,或者换句话说,我希望我的用户的数据即使在我的服务器完全受损的情况下也是安全的。因此,我让他们选择一个密码,并在将数据发送到应用程序之前在客户端对其数据进行加密。他们可以使用他们的用户 ID 检索他们的加密数据。嗯,这听起来不太安全,我可以下载任何人的加密数据并对它进行 运行 离线攻击。因此,让他们使用密码访问加密数据(我不希望他们必须记住两个不同的密码)。但这并不好,因为我有他们的密码才能解密他们的数据。因此,一个简单的解决方案是使用他们的密码加密他们的数据,并将其与他们的散列密码一起发送到服务器,正如答案中正确指出的那样 是 新密码服务器是相关的(所以服务器应该再次散列存储它等等)。然而,服务器无法解密客户端数据,因为它从来没有原始密码,但只有有效的人才能下载甚至他们的加密内容,他们只需要记住一个密码。 (请注意,这是一个非常简化的模型,实际上,还需要更多的东西,例如适当的密钥派生函数,而不仅仅是普通的哈希,但这是另一个更长的故事。)
不要误会我的意思,我并不是说您通常应该在客户端散列密码 - 不,另一个答案在这方面是正确的。我只是想证明 是 至少一个用例,其中客户端密码散列是一个有效选项。查看著名的密码管理器,有些工作方式类似。
100%说得通:其实这个概念已经被很多人提出来了,难的是正确实施。如果你做错了,会有很多陷阱,最直接的一个是容易受到 "pass-the-hash" 的攻击,正如@swa66 所描述的那样。为防止这种情况,您需要在两边进行散列。客户端哈希应该很慢(bcrypt、scrypt、argon2 或 pbkdf2),而服务器端哈希应该很快(sha256)。
编辑:许多人在不了解其工作原理的情况下对此投了反对票,所以我现在在这里包含基本细节(之前我只链接到它的工作原理) .这个想法是在客户端应用诸如 bcrypt 的慢散列,然后在服务器端应用诸如 SHA256 的快速散列。需要快速哈希来防止传递哈希攻击。在数据库泄漏的情况下,攻击者要么散列以反转快速散列(不可能 - 违反加密散列函数的单向 属性),要么将原像强行强制为快速散列(不可能 - - 大小是慢速散列输出的长度,例如 bcrypt 的 184 位),或者暴力破解慢速散列和快速散列的组合——这使攻击者回到相同的位置,就好像整个计算发生在服务器端。所以我们并没有通过将繁重的计算转移到客户端来降低数据库泄漏时密码攻击的安全性。
我在 Method to protect passwords in databases for web applications 中调查了很多这样的提案。此外,我分析了利弊并找出了以前没有发现的弱点(账户枚举),并提出了一种独特的安全方法。该研究建立在许多来源之上,包括:
- Secure authentication: partial client-side key stretching… please review/criticize my idea
- How to securely hash passwords? -- 请参阅客户端哈希部分
- Client side password hashing
- Discussion from various authors on Hacker News -- 查看来自 oleganza、mschuster91、crusso 等的评论...
你引用了 Twitter 的例子,GitHub 也做了类似的事情。当我写上面的论文时,防止服务器看到明文密码的最突出的例子是 Heartbleed,我在论文中对此进行了评论(第 1.3 节的底部)。
其他人随后进行了后续研究,确定了类似的想法 -- Example: Client-Plus-Server Password Hashing as a Potential Way to Improve Security Against Brute Force Attacks without Overloading the Server。没有人值得所有的赞誉,但主要的收获是,如果你安全地做这件事是个好主意,但你真的需要了解风险(如果你没有阅读研究,很容易不安全地做)。
我和我的一个朋友正在讨论我们是否应该在将 web 应用程序的用户密码发送到我们的服务器之前对其进行预散列。
我知道有多个问题已经处理了这个主题,但它们都是关于将它安全地传输到服务器的。我们的想法与传输安全性无关(我们使用 SSL),我们希望对客户端进行哈希处理以防止 "real" 密码到达我们的服务器。
这个想法是在 Twitter 宣布他们的错误导致密码以明文形式打印到日志文件时产生的。
我们目前正在讨论这个概念是否有意义,以及如果我们使用 SHA512 对其进行哈希处理,它会如何影响密码的安全性(就 Bruteforce 而言)。
TL;DR:
我们想在客户端对密码进行哈希处理,以防止我们的服务器以明文形式获取密码(我们使用 SSL 进行传输)。
这有意义吗?
哪种算法最适合用于哈希?
经过哈希处理的密码将在服务器端再次使用 bCrypt 进行哈希处理。
否!
密码学的第一条规则:不要自己发明它,否则你会犯可怕的错误。
这不是针对您个人的,目前为止不是:即使是一流的专家在精心设计新系统时也会犯错误。这就是为什么在任何东西成为标准之前,他们会多次对彼此的工作进行同行评审。由于在此类同行评审期间发现的问题,此类专家针对此类标准提出的许多提案都被重新制定。那么,为什么我们其他人不能进行凡人设计:没有人足够优秀来进行同行评审,因为专家不会碰它。
对密码客户端进行哈希处理
哈希客户端真的很糟糕,因为哈希变成了密码,现在你把它明文存储在服务器上。
如何设置密码
- 只存储哈希密码(暗示:将密码发送到服务器,只是不存储它)
- 使用盐并将其与密码一起存储(未加密)。 salt 本质上是一个随机字符串,在对其进行哈希处理之前将其连接到密码(以存储它并验证它)
使用慢散列。使用快速散列是一个常见且致命的错误,即使在使用盐时也是如此。人们知道的大多数散列函数,如 SHA-256、SHA-3 等,都是快速散列,完全不适合散列短的、可预测的项目,如密码,因为它们可以在极短的时间内被逆转。
多慢:尽可能慢。慢散列的例子: bcrypt,PBKDF-2(本质上是大量轮的a 快速散列使其变慢)
根据您的编程环境,有预制例程,请使用它们!
参考:
虽然 @swa66 概述了如何安全地管理密码,但请注意 是 可以考虑客户端密码散列的有效方案,所以不要盲目关注"best practice",先尝试了解一下。
假设我有一个存储用户数据的标准 Web 应用程序。在我的威胁模型中,我什至不希望我自己的用户必须信任我,或者换句话说,我希望我的用户的数据即使在我的服务器完全受损的情况下也是安全的。因此,我让他们选择一个密码,并在将数据发送到应用程序之前在客户端对其数据进行加密。他们可以使用他们的用户 ID 检索他们的加密数据。嗯,这听起来不太安全,我可以下载任何人的加密数据并对它进行 运行 离线攻击。因此,让他们使用密码访问加密数据(我不希望他们必须记住两个不同的密码)。但这并不好,因为我有他们的密码才能解密他们的数据。因此,一个简单的解决方案是使用他们的密码加密他们的数据,并将其与他们的散列密码一起发送到服务器,正如答案中正确指出的那样 是 新密码服务器是相关的(所以服务器应该再次散列存储它等等)。然而,服务器无法解密客户端数据,因为它从来没有原始密码,但只有有效的人才能下载甚至他们的加密内容,他们只需要记住一个密码。 (请注意,这是一个非常简化的模型,实际上,还需要更多的东西,例如适当的密钥派生函数,而不仅仅是普通的哈希,但这是另一个更长的故事。)
不要误会我的意思,我并不是说您通常应该在客户端散列密码 - 不,另一个答案在这方面是正确的。我只是想证明 是 至少一个用例,其中客户端密码散列是一个有效选项。查看著名的密码管理器,有些工作方式类似。
100%说得通:其实这个概念已经被很多人提出来了,难的是正确实施。如果你做错了,会有很多陷阱,最直接的一个是容易受到 "pass-the-hash" 的攻击,正如@swa66 所描述的那样。为防止这种情况,您需要在两边进行散列。客户端哈希应该很慢(bcrypt、scrypt、argon2 或 pbkdf2),而服务器端哈希应该很快(sha256)。
编辑:许多人在不了解其工作原理的情况下对此投了反对票,所以我现在在这里包含基本细节(之前我只链接到它的工作原理) .这个想法是在客户端应用诸如 bcrypt 的慢散列,然后在服务器端应用诸如 SHA256 的快速散列。需要快速哈希来防止传递哈希攻击。在数据库泄漏的情况下,攻击者要么散列以反转快速散列(不可能 - 违反加密散列函数的单向 属性),要么将原像强行强制为快速散列(不可能 - - 大小是慢速散列输出的长度,例如 bcrypt 的 184 位),或者暴力破解慢速散列和快速散列的组合——这使攻击者回到相同的位置,就好像整个计算发生在服务器端。所以我们并没有通过将繁重的计算转移到客户端来降低数据库泄漏时密码攻击的安全性。
我在 Method to protect passwords in databases for web applications 中调查了很多这样的提案。此外,我分析了利弊并找出了以前没有发现的弱点(账户枚举),并提出了一种独特的安全方法。该研究建立在许多来源之上,包括:
- Secure authentication: partial client-side key stretching… please review/criticize my idea
- How to securely hash passwords? -- 请参阅客户端哈希部分
- Client side password hashing
- Discussion from various authors on Hacker News -- 查看来自 oleganza、mschuster91、crusso 等的评论...
你引用了 Twitter 的例子,GitHub 也做了类似的事情。当我写上面的论文时,防止服务器看到明文密码的最突出的例子是 Heartbleed,我在论文中对此进行了评论(第 1.3 节的底部)。
其他人随后进行了后续研究,确定了类似的想法 -- Example: Client-Plus-Server Password Hashing as a Potential Way to Improve Security Against Brute Force Attacks without Overloading the Server。没有人值得所有的赞誉,但主要的收获是,如果你安全地做这件事是个好主意,但你真的需要了解风险(如果你没有阅读研究,很容易不安全地做)。