0

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 ホストに大混乱をもたらしました。

mongodb のハッシュのスクリーンショット

私の質問は、これhashをデータベースに保存するためのより良い/よりスマートな方法はありますか? でエンコードしようとしましたが、 User スキーマ.toString('hex')のタイプを に変更しようとしましたが、これらのアプローチは両方とも、ユーザーをログインさせようとするとすべての比較が false になりました。以下に示すように、関数で比較が行われます。hashbufferauthenticate

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.');
    });
}
4

1 に答える 1

1

ハッシュを 16 進文字列としてデータベースに保存しても問題ありません (StringまたはBufferプロパティに「生」で保存しても問題ありません)。

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同期の対応物があります)

于 2013-10-12T19:59:37.623 に答える