为什么 Ruby 的 bcrypt 库会在哈希中以明文形式包含 salt?

4
我正在使用Coda Hale的Ruby bcrypt库。最近我注意到它的工作方式与我想象的不同。我原以为正确的流程是:
  1. 生成一个盐
  2. 获取密码
  3. 将盐和密码字符串连接起来
  4. 通过哈希函数进行哈希处理
但当我查看bcrypt函数的结果时,似乎盐被连接到了哈希值而不是密码。也就是说,在第4步之后发生了盐串联,而不是在之前。我假设Coda Hale做得没错,但我想知道为什么会出现这种情况。
下面是一个简短的IRB会话,展示了一些奇怪的地方(对我来说)。请注意,在hash_secret函数的结果中,前29个字符与相同。如果有任何关于这种情况的信息,将不胜感激。
我的唯一理论是,盐被添加到哈希值中,同时也被嵌入其中,这样就不需要将盐单独存储在数据库字段中(本质上是一种记录打包策略)?
irb#1(main):004:0> password_salt = BCrypt::Engine.generate_salt
=> "$2a$10$OrKdcWORLL8Gorhy9XR3UO"
irb#1(main):005:0> password='abc'
=> "abc"
irb#1(main):006:0> BCrypt::Engine.hash_secret(password, password_salt)
=> "$2a$10$OrKdcWORLL8Gorhy9XR3UOY8Sebzq92m7r02XPitzoazPdO7tmsEO"
irb#1(main):007:0> 

2
这样做是为了不必将盐单独存储于哈希之外。盐已经与密码连接起来生成哈希,但随后还将盐额外连接到哈希上(以及有关哈希算法的其他元数据),以便只需要单个字符串即可测试哈希。 - Michael Berkowski
1
此外,bcrypt如何具有内置盐?,这可能是一个更好的资源。 - Michael Berkowski
@MichaelBerkowski - 同意 - 我希望在提问之前看到那个第二个问题(我确实进行了搜索!)。我已投票将其标记为重复,因为它回答了我的具体问题。 - Steve Midgley
1个回答

4

从技术上讲,这没有任何问题。如果您愿意,可以将盐和密码分开存储。甚至,您可以将盐公开。我听说有些人会使用用户ID作为盐来节省数据库中的存储空间。

在同一数据库中将哈希值和盐存储在不同字段中并不能提高安全性。唯一重要的是每个盐都是唯一的,以防止彩虹表攻击。

我想创建者决定将两个字符串连接在一起只是为了将盐和哈希值保存在单个字段中,方便在数据库或应用程序中使用。有时这很有用,例如在不支持多值返回的语言中。


4
这也是 UNIX 类型系统中保存密码的方法,其中有一个单一的字段用于存储散列密码。该字符串包括有关散列方法、盐和按照相当标准格式的哈希的信息。这样,如果您将来更改散列方法,旧的散列密码仍将起作用。值得注意的是,如果不知道盐和散列方法,则无法重新生成哈希。 - tadman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接