【问题标题】:How to store crypto pbkdf2 in mongoDB?如何在 mongoDB 中存储加密 pbkdf2?
【发布时间】:2013-10-13 03:59:37
【问题描述】:

按照 Express 的身份验证示例,我正在使用以下函数对用户密码进行哈希处理:

function hash(pwd, salt, fn) {
    // Bytesize
    var len = 128,

    // Iterations. ~300ms
        iterations = 12000;

    if (3 == arguments.length) {
        crypto.pbkdf2(pwd, salt, iterations, len, fn);
    } else {
        fn = salt;
        crypto.randomBytes(len, function(err, salt){
            if (err) return fn(err);
            salt = salt.toString('base64');
            crypto.pbkdf2(pwd, salt, iterations, len, function(err, hash){
                if (err) return fn(err);
                fn(null, salt, hash);
            });
        });
    }
}

如您所见,salt 以 base64 编码的字符串形式返回。但是,hash 返回为SlowBuffer。在尝试登录用户时,同样的函数也用于比较哈希值。

我的用户 Mongoose 模式指定 hash 应该是 String 类型。这最终以一种奇怪的方式存储哈希,导致这样的内容对我的 mongo 主机造成了严重破坏:

我的问题是,有没有更好/更智能的方法将此hash 存储在我的数据库中?我已经尝试使用.toString('hex') 对其进行编码,并且我还尝试将用户架构中的hash 类型更改为buffer,但是这两种方法在尝试登录用户时都使所有比较错误。进行了比较在我的authenticate 函数中,如下所示:

function authenticate(name, pass, fn) {
    var findUser = function(username) {
        var deferred = Q.defer(),
            populateObj = [
                // list of paths to populate objects normally goes here
            ];
        User.findOne({ username: name }).populate(populateObj).exec(function (err, retrievedUser) {
            if (err || !retrievedUser) {
                console.log(err);
                deferred.reject('Cannot find user.');
            }
            else {
                deferred.resolve(retrievedUser);
            }
        });

        return deferred.promise;
    };

    findUser(name).then(function(data) {
        // apply the same algorithm to the POSTed password, applying
        // the hash against the pass / salt, if there is a match we
        // found the user
        hash(pass, data.salt, function(err, hash){
            if (err) return fn(err);
            if (hash == data.hash) return fn(null, data);
            return fn('Invalid password.');
        });
    }, function() {
        return fn('Failed to retrieve user.');
    });
}

【问题讨论】:

  • 如何进行实际比较?你能显示这些代码吗?
  • @robertklep 编辑添加authenticate 函数,用于比较

标签: node.js mongodb mongoose


【解决方案1】:

将散列作为十六进制字符串存储在数据库中对我来说没问题(将它们“原始”存储在 StringBuffer 属性中都不行):

var crypto      = require('crypto');
var mongoose    = require('mongoose');
var client      = mongoose.connect('mongodb://localhost/test');
var UserSchema  = new mongoose.Schema({
  salt  : String,
  hash  : String
});

var User = mongoose.model('User', UserSchema);

hash('secret', function(err, salt, key) {
  new User({ salt : salt, hash : key.toString('hex') }).save(function(err, doc) {
    User.findById(doc._id, function(err, doc) {
      hash('secret', doc.salt, function(err, key) {
        console.log('eq', doc.hash === key.toString('hex'));
      });
    });
  });
});

(顺便说一句,crypto.pbkdf2crypto.randomBytes 都有同步对应项)

【讨论】:

  • 这行得通。当我之前尝试过这个时,我在尝试登录用户时一定没有调用toString('hex')。另外,我知道他们有同步对应项,我在应用程序的另一部分使用它们。谢谢!
猜你喜欢
  • 2014-10-20
  • 2012-07-28
  • 2014-10-13
  • 2017-04-10
  • 2013-09-10
  • 1970-01-01
  • 1970-01-01
  • 2013-05-19
  • 1970-01-01
相关资源
最近更新 更多