NodeJS 升级现有的bcrypt散列轮数

ecbunoof  于 2023-03-01  发布在  Node.js
关注(0)|答案(2)|浏览(149)

我有一个数据库,其中大多数散列的轮数对于我们的用例来说太低了。我想升级这些到一个更高的轮数/迭代数,希望使用node.bcrypt.js库。
示例:
我的数据库里有类似的东西

'$2a$05$Ss068.p/.i4IRzrYoLM/U.ETLpzwrBs2vVfViqgfC5bI4i3BGClZC' 
   //From: bcrypt.hashSync("hello world", 5)

我希望它变成这样:

'$2a$10$6sZOFUEWdVMHoCsgF0k1..RhwoD7VmLlLc5.67/Qw81/XuSuNIOcO'
  //From: bcrypt.hashSync("hello world", 10)

有什么方法可以做到这一点吗?我想api可能看起来像这样:

//Non-existing api;
var hash = '$2a$05$Ss068.p/.i4IRzrYoLM/U.ETLpzwrBs2vVfViqgfC5bI4i3BGClZC';
const roundCount = 10
bcrypt.upgradeHashRoundCount(hash, roundCount)
  .then(function(upgradedHash){
    console.log(upgradedHash)
  })
  .catch(function(error){
    console.error("Not a bcrypt hash, or has higher round-count than provided round count")
  })

编辑以澄清:
我想做一个批处理的工作,我获取所有的哈希值,并对每个哈希值进行升级,而不需要原始密码,因为bcrypt本质上只是循环,我认为理论上应该有可能进行更多的循环,并将其存储回来。

qvtsj1bj

qvtsj1bj1#

我想到了几种方法,bcrypt的好处是轮数存储在salt本身中,因此彼此独立,这意味着你可以在不破坏旧密码的情况下平滑地转换。
所以有两个建议:

  • 你可以开始使用更高的盐为所有新的密码/密码的变化。优点显然是,你只需要增加哈希轮,你就完成了。缺点是,它可能需要永远,直到所有的密码存储与更高的轮。
  • 你可以在每次成功登录时更新密码,如果他们仍然有较低的轮数。你可以使用getRounds(hash)。这样你的密码将得到更新非常快(只要他们成功使用一次)

像这样的东西:

function checkPw(pw, user) {
  return bcrypt.compare(pw, user.hash)
  .then(success => {
    if(success && bcrypt.getRounds(hash) < 10) {
      return updateHash(pw, user).then(() => success);
    }
    return success;
  })
}

function updateHash(pw, user) {
  return bcrypt.hash(pw, 10).then((newHash) => {
    user.hash = newHash;
    // update user in db
    return user.save();
  });
}

checkPw('abc', {
  id: 123,
  hash: '$2a$04$7AiVQRTAEPWFwldS7CB6VuQcMSenrPlpoEEGdMyQDE8BxcxcJXPgG'
})
ddarikpa

ddarikpa2#

**免责声明:**我绝不是密码学Maven,而是bcrypt的最终用户,所以我不能给予任何建议,如果这是密码学的声音。

我目前正在研究选项,因为我们可能也想改变我们的设置-约翰内斯梅尔兹的两个建议似乎是最务实的我,特别是重新计算哈希成功登录。
不过,我们可能会面临你所描述的问题--非活动用户也应该迁移到一个更强的散列中。根据this的回答,仅仅基于给定的散列来增加轮数是可能的。
然而,工作的是“散列散列”的方法。

在脱机作业中执行以下步骤:

1.给定一个现有的哈希值,提取盐:

oldSalt = hashedPassword.substring(0, hashedPassword.lastIndexOf('$') + 23)

(the salt的长度为22个字符,从最后一个$之后开始)
1.使用新设置对现有散列进行散列(即使用更高的计数)

hashedHashedPassword = bcrypt.hash(hashedPassword, 12)

1.在数据库中,同时存储oldSalthashedHashedPassword,并丢弃hashedPassword

用户登录时执行以下步骤:

1.在用户下次登录时,使用oldSalt散列suppliedPassword输入,然后照常进行比较:

oldHash = bcrypt.hash(suppliedPassword, oldSalt)
result = bcrypt.compare(oldHash, hashedHashedPassword)

1.如果result成功,则通过散列明文密码来消除“双重散列”:

hashedPassword = bcrypt.hash(suppliedPassword)

保存给定帐户的hashedPassword,并删除oldSalthashedHashedPassword
要考虑的缺点:

  • 事实上,它仍然是一个滚动迁移,但其优点是所有现有的散列都将一次升级
  • 登录代码中可能需要永久保留的额外分支逻辑,额外的DB列
  • 以后再升级发数,会出现hashedHashedHashedPassword + oldSalt1oldSalt2、......

相关问题