node.bcrypt.js如何比较哈希密码和无密码的明文密码?


95

来自github

哈希密码:

var bcrypt = require('bcrypt');
bcrypt.genSalt(10, function(err, salt) {
    bcrypt.hash("B4c0/\/", salt, function(err, hash) {
        // Store hash in your password DB.
    });
});

要检查密码:

// Load hash from your password DB.
bcrypt.compare("B4c0/\/", hash, function(err, res) {
    // res == true
});
bcrypt.compare("not_bacon", hash, function(err, res) {
    // res = false
});

从上面看,比较中如何不包含盐值?我在这里想念什么?

Answers:


95

盐被合并到哈希中(作为明文)。比较功能只是将盐从哈希表中提取出来,然后使用它来哈希密码并执行比较。


1
我还是不明白 在比较过程中,如果不向哈希提供盐,它如何知道哈希的哪一部分?
2014年

6
bcrypt是一个标准,始终将盐和哈希以相同的格式连接在一起。您在加密时提供盐,并将其合并到哈希中。bcrypt将只能解密最初使用bcrypt加密的数据,否则,您是对的-它无法知道哪个部分是哈希,哪个部分是盐。
法案

4
好的,我们知道了:盐与哈希一起存储。bcrypt是开源的,因此这意味着每个人都知道它存储它的精确程度。因此,您知道如何提取它,或如何从纯文本密码生成哈希。这如何帮助保护密码以防扫描彩虹表中的哈希值,而哈希表基本上是盐的主要思想?
Vitaliy Lebedev

13
攻击者是否知道任何特定哈希值的盐都没关系,这不是秘密。每个密码使用不同的盐值意味着攻击者无法使用通用值预先计算哈希值。由于每个盐都有不同的含义,因此他们需要为每个密码重新计算任何表,这使它们无用。
条例草案

3
以这种方式看,攻击者是否知道这样的数据库中某些用户的盐就很重要:column_password = hash, column_salt = saltvs column_password = hash_salt。攻击者仍然拥有相同的信息。重点是使每个密码如此随机且更大,以至于不可能有人预先计算出它。
Muhammad Umer

27

我也有与原始海报相同的问题,它看起来有点环顾四周,并尝试了不同的方法来理解该机制。正如其他人已经指出的那样,盐被连接到最终的哈希表中。因此,这意味着两件事:

  1. 该算法必须知道盐的长度
  2. 还必须知道盐在最终字符串中的位置。例如,如果从左侧或右侧偏移了特定数字。

这两件事通常在实现中进行硬编码,例如bcryptjs的bcrypt实现源将盐长度定义为16

/**
* @type {number}
* @const
* @private
*/

var BCRYPT_SALT_LEN = 16;

因此,为了说明该想法背后的基本概念,如果有人想手动进行操作,它将类似于以下内容。如果有可以使用的库,我不建议您自己实现这样的事情。

var salt_length = 16;
var salt_offset = 0;

var genSalt = function(callback)
{
    var alphaNum = '0123456789abcdefghijklmnopqurstuvwxyzABCDEFGHIJKLMNOPQURSTUVWXYZ';
    var salt = '';
    for (var i = 0; i < salt_length; i++) {
        var j = Math.floor(Math.random() * alphaNum.length);
        salt += alphaNum[j];
    }
    callback(salt);
}

// cryptographic hash function of your choice e.g. shar2
// preferably included from an External Library (dont reinvent the wheel)
var shar2 = function(str) {
    // shar2 logic here 
    // return hashed string;
}

var hash = function(passwordText, callback)
{
    var passwordHash = null;
    genSalt(function(salt){
        passwordHash = salt + shar2(passwordText + salt);
    });

    callback(null, passwordHash);
}

var compare = function(passwordText, passwordHash, callback)
{
    var salt = passwordHash.substr(salt_offset, salt_length);
    validatedHash = salt + shar2(passwordText + salt);

    callback(passwordHash === validatedHash);   
}

// sample usage
var encryptPassword = function(user)
{
    // user is an object with fields like username, pass, email
    hash(user.pass, function(err, passwordHash){
        // use the hashed password here
        user.pass = passwordHash;
    });

    return user;
}

var checkPassword = function(passwordText, user)
{
    // user has been returned from database with a hashed password
    compare(passwordText, user.pass, function(result){
        // result will be true if the two are equal
        if (result){
            // succeeded
            console.log('Correct Password');
        }
        else {
            // failed
            console.log('Incorrect Password');
        }
    });
}

0

因为我本人也有同样的问题,所以我确切地知道您在想什么。

您对加密算法中使用的“秘密密钥”和用于减慢加密过程并使黑客更难使用蛮力的“盐” 存在误解。

当您使用普通密码和盐生成哈希时,该哈希将密码本身用作秘密密钥!因此,下次您尝试将其与普通密码进行比较时,此普通密码必须与用于生成哈希的密码完全相同!这就是为什么您不必将其存储在其他地方的原因,因为它始终由用户在注册和登录步骤中提供!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.