比较两个密码哈希值--nodejs

10

我正在使用加密https://nodejs.org/api/crypto.html进行密码加密和身份验证。 我正在处理更改密码页面,但无法确定用户提供的密码是否具有与现有密码相同的哈希值。以下是我的代码。

var createSalt = function createSalt() {
    return crypto.randomBytes(128).toString('base64');
};

var hashPwd = function hashPwd(salt, pwd) {
    var hmac = crypto.createHmac('sha256', salt);
    return hmac.update(pwd).digest('hex');
};

//use password , create salt, hash and compare with the existing
var salt = createSalt();
var passHash = hashPwd(salt,data.Password);
console.log('the password is', user.PassHash === passHash);

我期望控制台信息输出为true,表示现有用户的密码匹配。但是,这两个哈希值似乎根本不匹配。请问我漏了什么?我该如何实现这一点?我想确保用户在更改新密码之前与其现有密码匹配。非常感谢任何帮助。

2个回答

17
我认为你的问题在于盐。通常情况下,你需要存储第一次哈希时使用的盐,并在第二次使用相同的盐。盐的原因是为了确保哈希值不会映射到原始密码,如果黑客使用彩虹表攻击从受损系统中检索密码。请参见我们为什么要使用“盐”来保护我们的密码? 如果你尝试
var salt = crypto.randomBytes(128).toString('base64');

var hashPwd = function hashPwd(salt, pwd) {
    var hmac = crypto.createHmac('sha256', salt);
    return hmac.update(pwd).digest('hex');
};

//use password , create salt, hash and compare with the existing
var passHash = hashPwd(salt,data.Password);
console.log('the password is', user.PassHash === passHash);

只要您不重新启动服务器(假设您将“salt”变量存储在响应http请求的函数作用域之外),它就可以正常工作。
更好的解决方案(在我看来)是bcrypt所做的。在那里,您为每个密码生成一个盐,但要验证密码是否正确,您使用compare,该函数使用哈希中存储的盐。这样,您可以对每个密码使用不同的盐,这意味着您不必太担心盐被泄露的问题。
npm install bcrypt

var bcrypt = require('bcrypt');
var hash = bcrypt.hashSync("my password");

bcrypt.compareSync("my password", hash); // true
bcrypt.compareSync("not my password", hash); // false

还有compareAsync和其他异步变量。另请参见:https://www.npmjs.com/package/bcrypt-nodejs


哦,谢谢iwein,那我应该使用相同的盐对吧。我的意思是,不要创建新的盐,而是使用现有密码中的盐。? - Nuru Salihu
@NuruSalihu 是的,我理解就是这样。如果你的盐被盗了,你必须重置所有密码并重新生成盐。通常加密库允许你比较密码而不需要再次传递盐(它们将盐存储在散列密码内部)。例如,bcrypt 就是这样做的。https://dev59.com/GWw15IYBdhLWcg3wGn5c - iwein
@iwein 这个链接说的是相反的:https://crackstation.net/hashing-security.htm 重复使用盐不是一个好习惯。在第四部分中解释了为什么。你认为这篇文章是正确的吗?我对这整个事情都很陌生,但觉得这可能会有所帮助。 - Guilherme L. Moraes
4
不应该使用对时间攻击敏感的 === 来比较哈希值。应该使用 crypto.timingSafeEqual - Tofandel

0
 UserSchema.pre('save', function (next) {
  if (this.password) {
    const salt = bcrypt.genSaltSync(10);//or your salt constant
    this.password = bcrypt.hashSync(this.password, salt);
  }
  next();
});

在你的控制器中
  const result = bcrypt.compareSync(req.body.password, your_hash_password);
      if (result){
        return res.json(message: "success");
      } else {
        return res.status(400).json("Bad request. Password don't match ");
      }

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