【问题标题】:nodejs - how to compare two hashes password of bcryptnodejs - 如何比较bcrypt的两个哈希密码
【发布时间】:2019-09-12 01:57:25
【问题描述】:

您好,在我搜索解决方案后我需要一些帮助来解决这个问题,但我还没有找到,

我想将 2 个哈希密码与相同密码的 bcrypt 进行比较, 我该怎么做?

例如:

我有这 2 个哈希密码来自 bcrypt 中的相同密码:

var password = E@Js#07Do=U$
var hash1 = $2a$10$fKAyjaG0pCkisZfRpKsBxursD6QigXQpm1TaPBDZ4KhIZRguYPKHe
var hash2 = $2a$10$mgApOcRIp7RSK3lRIIlQ5e/GjVFbxAFytGAEc0Bo17..r8v2pPR22
// that's not working for me
bcrypt.compare(passwordHash, userPasswordLoginHash, function(err, isMatch) {
   if (err) throw err;
   if(isMatch){
      console.log('correct password!')
   }
   callback(null, isMatch);
});

我如何比较它们,以确定它们来自相同的密码,通过使用 bcryptjs npm 包?

【问题讨论】:

  • 我认为您只能将纯文本密码与散列密码进行比较

标签: javascript node.js hash passwords bcrypt


【解决方案1】:

这在设计上是不可能的 - 作为真正密码散列的核心安全属性。

如果你可以在不知道原始密码的情况下比较两个密码哈希,那么如果攻击者在系统上破解了一个密码,他们就会立即知道的密码>所有个使用该密码的用户,无需任何额外工作。为什么这将是一件坏事应该立即显而易见。

例如,如果使用不适合密码存储的哈希存储密码(例如 MD5),那么如果 50 个用户的密码为“password”,那么他们所有的哈希密码将具有相同的 MD5 哈希('5f4dcc3b5aa765d61d8327deb882cf99 '),破解其中一个会泄露每个用户的密码

你不能用像 bcrypt 这样的现代密码哈希来做到这一点。 “比较”两个现代密码哈希的唯一方法是提前知道明文,然后使用每个哈希中的盐应用算法。即使两个用户的密码相同,攻击者也必须执行相同的昂贵计算来独立破解每个用户,因为唯一的盐使每个哈希值都是唯一的。

更一般地说——这听起来可能有点大胆——但没有任何系统或管理员可以比较两个不同用户的密码的合法用例。用户密码一旦存储,就应该 100% 独立并且对系统 100% 不透明。如果系统或业务案例需要这种比较,则应重新设计以消除这种要求。

【讨论】:

  • 其实是有用例的。例如,我正在对匿名用户 ID 进行哈希处理,但是为了知道两个帖子是由客户端的同一用户发布的,我想比较他们的哈希 ID...
  • 有趣。那不是密码哈希。目的是防止任何人关联同一用户发布的每个帖子吗?如果是这样,您必须独立破解它们才能建立这种相关性。但是,如果您的目标是准匿名但允许直接关联同一用户发布的帖子(因为在其他地方使用了tripcode),那么除非您强制哈希具有相同的盐,否则您将无法直接比较在不知道用户名或破解它们的情况下,这两个哈希值。换句话说,该方法与用例不匹配——正如我所建议的那样。
  • 参见。行程码匿名使用:tanasinn.info/wiki/…。您可以为此使用 bcrypt ...但您必须保持 salt 常量,以便两个哈希值相同。
  • 如果用户更改了他们的密码,并且您想验证他们没有重复使用他们最后的任何密码,比如 24 个密码,该怎么办?您需要存储前 24 个密码哈希值,并将新密码与每个哈希值进行比较。理想情况下,您不希望为 24 次检查中的每一次都重新散列新密码。
  • 正是通常如何完成密码历史验证。如果有一件事比不散列某人的当前密码更糟糕,那就是不散列他们的密码历史,允许攻击者研究所有以前的密码,并披露如何的心理用户选择密码。
【解决方案2】:

使用bcrypt lib,您可以将纯文本密码与使用相同 lib 散列的密码进行比较。

假设你散列了一个密码

const myPlaintextPassword = 'E@Js#07Do=U$'
bcrypt.hash(myPlaintextPassword, saltRounds, function(err, hash) {
  // Store hash in your password DB.
  // example output, taking your hash
  // hash = $2a$10$fKAyjaG0pCkisZfRpKsBxursD6QigXQpm1TaPBDZ4KhIZRguYPKHe
});

你比较喜欢:

// db query, get hashed password, found hash
// hash = $2a$10$fKAyjaG0pCkisZfRpKsBxursD6QigXQpm1TaPBDZ4KhIZRguYPKHe
// User input again:
const myPlaintextPassword = 'E@Js#07Do=U$'
bcrypt.compare(myPlaintextPassword, hash, function(err, res) {
  // res is true as the original password is the same
  // res == true
});

【讨论】:

  • 我认为问题不在于如何验证密码,而在于如何比较两个哈希以查看它们是否是相同的密码。
  • 你已经回答了那部分:)。添加如何比较,以防 OP 对实现密码验证感到困惑
【解决方案3】:

“使用 bcrypt lib,您可以将纯文本密码与使用相同 lib 散列的密码进行比较。”

问题在于微服务架构,它非常不安全。如果我有一个前端将一个未经哈希处理的密码传递给后端,那么在与系统后端数据库中的哈希值进行比较之前,未经哈希处理的密码会被记录(可能在多个地方)。

【讨论】:

  • 是的,它不一定是微服务架构。任何使用 bcrypt 的架构基本上都会涉及通过网络传递明文密码? (https 有帮助,但不是灵丹妙药)
  • 这不是微服务架构的错,而是实现方式的错。它不应该记录那些字段,句号。
  • 在实践中也同意这实际上会造成不安全的明文密码存储/传输
  • 许多日志库都提供过滤器,因此您必须传递一个记录器实例和当前密码以被过滤掉。您甚至可以自己轻松编写一个包装器。但是,当然,这并不能真正保证这个过滤器在任何地方都能正确应用。正如@jwenting 所说,“永远不应该”在涉及安全问题时是一个不充分的前提。
猜你喜欢
  • 2016-09-13
  • 2017-09-05
  • 2019-11-11
  • 2017-09-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-25
相关资源
最近更新 更多