718

Coda Hale 的文章“如何安全地存储密码”声称:

bcrypt 内置了盐以防止彩虹表攻击。

他引用了这篇论文,其中说在 OpenBSD 的实现中bcrypt

OpenBSD 从一个 arcfour (arc4random(3)) 密钥流生成 128 位 bcrypt salt,并使用内核从设备时序收集的随机数据播种。

我不明白这是怎么回事。在我对盐的概念中:

  • 每个存储的密码都需要不同,因此必须为每个密码生成单独的彩虹表
  • 它需要存储在某个地方以便可重复:当用户尝试登录时,我们会尝试输入他们的密码,重复我们最初存储密码时所做的相同的盐和哈希过程,然后比较

当我使用带有 bcrypt 的 Devise(Rails 登录管理器)时,数据库中没有 salt 列,所以我很困惑。如果盐是随机的并且没有存储在任何地方,我们如何可靠地重复散列过程?

简而言之,bcrypt 怎么能有内置的 salts呢?

4

5 回答 5

895

这是 bcrypt:

生成随机盐。“成本”因素已预先配置。收集密码。

使用盐和成本因子从密码中派生加密密钥。用它来加密一个众所周知的字符串。存储成本、和密文。因为这三个元素的长度是已知的,所以很容易将它们连接起来并将它们存储在一个字段中,然后可以将它们分开。

当有人尝试进行身份验证时,检索存储的成本和盐。从输入的密码、成本和盐中派生出一个密钥。加密相同的众所周知的字符串。如果生成的密文与存储的密文匹配,则密码匹配。

Bcrypt 的运行方式与基于 PBKDF2 等算法的更传统方案非常相似。主要区别在于它使用派生密钥来加密已知的纯文本。其他方案(合理地)假设密钥派生函数是不可逆的,并直接存储派生密钥。


存储在数据库中的bcrypt“哈希”可能如下所示:

$2a$10$vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa

这实际上是三个字段,由“$”分隔:

  • 2a标识使用的bcrypt算法版本。
  • 10是成本因素;2使用了密钥派生函数的10次迭代(顺便说一句,这还不够。我建议使用 12 次或更多的成本。)
  • vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa是盐和密文,在修改后的 Base-64 中连接和编码。前 22 个字符解码为 salt 的 16 字节值。其余字符是要进行比较以进行身份​​验证的密文。

此示例取自Coda Hale 的 ruby​​ 实现的文档。

于 2011-07-26T16:11:59.347 回答
200

我认为这句话应该措辞如下:

bcrypt在生成的哈希中内置了盐,以防止彩虹表攻击。

bcrypt实用程序本身似乎没有维护盐列表。相反,盐是随机生成的,并附加到函数的输出中,以便以后记住它们(根据Java 的实现bcrypt)。换句话说,产生的“哈希”不仅仅是bcrypt哈希。相反,它是哈希盐的连接。

于 2011-07-26T15:34:14.567 回答
3

为了让事情更清楚,

注册/登录方向 ->

密码 + salt 使用从成本、salt 和密码生成的密钥进行加密。我们称该加密值为cipher text. 然后我们将盐附加到这个值并使用 base64 对其进行编码。附加成本,这是生成的字符串bcrypt

$2a$COST$BASE64

该值最终被存储。

攻击者需要做什么才能找到密码?(其他方向 <- )

如果攻击者控制了数据库,攻击者将轻松解码 base64 值,然后他将能够看到盐。盐不是秘密。虽然它是随机的。然后他将需要解密cipher text.

更重要的是:在这个过程中没有散列,而是 CPU 昂贵的加密 - 解密。因此彩虹表在这里不太相关。

于 2020-06-07T08:22:50.773 回答
3

这是一个简单的术语...

Bcrypt没有存储盐的数据库......

盐以 base64 格式添加到哈希中......

问题是 bcrypt 在没有数据库时如何验证密码...?

bcrypt 所做的是它从密码哈希中提取盐......使用提取的盐来加密纯密码,并将新哈希与旧哈希进行比较,看看它们是否相同......

于 2021-05-02T20:26:05.353 回答
0

Lets imagine a table that has 1 hashed password. If hacker gets access he would know the salt but he will have to calculate a big list for all the common passwords and compare after each calculation. This will take time and he would have only cracked 1 password.

Imagine a second hashed password in the same table. The salt is visible but the same above calculation needs to happen again to crack this one too because the salts are different.

If no random salts were used, it would have been much easier, why? If we use simple hashing we can just generate hashes for common passwords 1 single time (rainbow table) and just do a simple table search, or simple file search between the db table hashes and our pre-calculated hashes to find the plain passwords.

于 2021-10-18T00:51:10.160 回答