密码哈希+盐如何工作

16

我曾经以为自己理解了密码哈希和盐的概念,但现在似乎有一些误解。我正在使用nodejs创建一个网站用户账户系统。

按照我的理解,当用户创建一个密码时,我们会生成一个随机的盐值,将其附加到密码上,再对这个字符串进行哈希处理。我们还可以添加一个工作因素来使哈希处理变慢,并防御暴力攻击。我们将盐值和哈希值一起存储在数据库中,为了验证登录尝试,我们需要在服务器端重复以上过程,使用存储的盐值和尝试的密码进行检查,看看哈希值是否匹配。

然而,看来nodejs中的bcrypt模块与我对哈希的理解不太一样。这是来自http://codetheory.in/using-the-node-js-bcrypt-module-to-hash-and-safely-store-passwords/的例子。

var salt = bcrypt.genSaltSync(10);
var hash = bcrypt.hashSync("my password", salt);

首先,为什么在盐中应用工作因子而不是哈希中?如果有人正在使用暴力破解攻击,他们会运行哈希函数,对吗?难道我们需要使慢的不是哈希函数吗?

我也对bcrypt的验证感到困惑:

bcrypt.compareSync("my password", hash);

即使两个用户选择了相同的密码,我们仍需要哈希值是唯一的,这就是盐的作用,对吗?那为什么我们不这样做呢?

bcrypt.compareSync("my password"+salt, hash);

1
盐的主要目标是防止彩虹表攻击,即预先计算盐到密码的映射,从而将破解的复杂度降低到“originalPassword = rainbowTable[hash]”。许多盐甚至更好,但并不是所有系统都使用超过一个盐。 - Brigand
2个回答

6

SALT 是一个2的次方数(从4到31)- 迭代函数创建哈希的循环次数。 bcrypt 取盐值,将其乘以2的salt次方。并将此值用于实现解码函数对我们的字符串进行total amount次操作。这是bcrypt函数中循环的“舍入值”。 每次执行以下操作时:

bcrypt.hashSync("my password", salt)

bcrypt是一种哈希算法,每次使用相同的输入字符串和相同的salt时,都会创建一个新的“随机”字符串,并生成不同的输出字符串。这是bcrypt函数工作的关键思想,我们将保存这些结果到我们的数据库中。 然后我们可以使用:

bcrypt.compareSync("my password", hash);

compareSync函数用来判断哈希值是否由字符串"my password"创建。如果我们在compareSync函数中添加盐(salt)到字符串"my password"中,我们将改变原始字符串,并且不能以这种方式获得true。因为bcrypt将比较hash,就好像它是这样创建的:

bcrypt.hashSync("my password"+salt, salt);

因此,我们应该使用以下结构:

  • 在创建用户数据时创建哈希值: var salt = bcrypt.genSaltSync(10); var hash = bcrypt.hashSync("my password", salt);
  • hash 保存到数据库中
  • 下一步,在登录期间对用户进行身份验证,如下所示:

    bcrypt.compareSync("my password", hash);

没有任何 salt 或参数。


3

salt 包含轮数,因此 bcrypt.hash(Sync) 函数知道它需要进行多少轮。 因此,hash 不是简单的哈希值,而是一个嵌入有 salt 的容器。


2
好的,这很有道理。那么这是否意味着我不需要在我的数据库中存储一个盐字符串?我只需要存储hashSync('pw',salt)的返回值,其中包含了盐,这就是为什么我们没有显式地传递盐给compareSync的原因? - gloo

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