为什么compareSync不需要盐字符串?

11

我正试图使用bcryptjs生成用户密码的哈希值。但是,在一件事上我有点困惑。

根据这篇文章,传统上我们需要:

  • 保持我们密码哈希的盐相对长和唯一,
  • 用这个盐腌制用户密码后进行哈希,
  • 同时存储搀着盐的哈希密码。

因此,当我们在验证用户时比较哈希值时,我们将存储的盐附加到用户输入的密码中,并将其与数据库中的哈希值进行比较。

然而,使用bcryptjs的hashSync和compareSync如下:

//hashSync to generate hash
var bcrypt = require('bcryptjs');
var password = "abc";
var hash = bcrypt.hashSync( <some string>, < integer length of salt>) // the salt of mentioned length(4-31) is self-generated which is random and fairly unique

//compareSYnc to compare hash
var testString="abc";
console.log(bcrypt.compareSync(testString, hash)) // compares with previously generated hash returns "true" in this case.

我困惑的是,如果我们在认证时不需要盐,那么生成它的意义是什么?compareSync 在没有访问盐的情况下返回 true。那么相对较小密码的暴力攻击不会变得更容易吗?无论盐的大小如何,以下所有内容都将返回 true:

console.log(bcrypt.compareSync("abc", bcrypt.hashSync("abc"))); // consoles true. by default, if salt size is not mentioned, size is 10.
console.log(bcrypt.compareSync("abc", bcrypt.hashSync("abc", 4))); //consoles true
console.log(bcrypt.compareSync("abc", bcrypt.hashSync("abc", 8))); //consoles true
console.log(bcrypt.compareSync("abc", bcrypt.hashSync("abc", 32))); //consoles true
console.log(bcrypt.compareSync("ab", bcrypt.hashSync("abc", 4))); //consoles false

我希望我的困惑能够被解释清楚。

1个回答

11

bcrypt标准使得存储盐值变得简单 - 检查密码所需的所有信息都存储在输出字符串中。

在影子密码文件中哈希字符串的前缀"$2a$"或"2y"表示该哈希字符串是以模块化加密格式的bcrypt哈希。 哈希字符串的其余部分包括成本参数、一个128位的盐(以Base64编码为22个字符)和192位[dubious - discuss]哈希值(以Base64编码为31个字符)。

以上内容来自于bcrypt 的 Wikipediapage 页面


我对Salt的理解,正如我在上面提到的文章中所述,它也会与原始密码连接起来,因此即使是非常短的密码也很难使用暴力破解。例如:如果密码是“a”,而盐是32个字符长,则需要对33个字符进行暴力破解,对吗?但是使用bcrypt,如果未存储盐,则匹配任何原始字符,无论盐的长度如何。例如,第一次尝试“a”就会返回true,无论盐的长度如何。那么,如果bcrypt未存储盐,除了防止彩虹表和反向查找表攻击之外,盐的用途是什么呢? - Pravin
6
哈希一个1个字符密码和一个33个字符密码之间的差别非常小甚至可以忽略不计。盐值是被储存的——它只是储存在包含哈希值的同一个字符串中。盐只是用来防止彩虹表攻击的,这就是它们的全部作用。 - Aaron Dufour

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