Node.js中的密码散列

时间:2016-06-27 02:18:02

标签: node.js

这是我当前的密码散列代码并保存到数据库:

var config = {
  hashBytes: 64,
  saltBytes: 64,
  iterations: 8000
};

crypto.randomBytes(config.saltBytes, function(err, salt) {

  crypto.pbkdf2(password, salt, config.iterations, config.hashBytes,
      function(err, hash) {

          var combined = new Buffer(hash.length + salt.length + 8);

          combined.writeUInt32BE(salt.length, 0, true);
          combined.writeUInt32BE(config.iterations, 4, true);
          salt.copy(combined, 8);
          hash.copy(combined, salt.length + 8);

          callback(combined);
      });
  });

代码的目标是将salt与哈希一起保存到数据库中的一个字段。这是否可以在数据库中的相同字段中存储密码/ salt?我很久以前就找到了这个算法,现在我不确定我是否理解这一点。

据我所知,首先我们创建一个缓冲区,它有足够的空间来存储哈希,盐,迭代次数和盐长度(不知道为什么我们在这里加8):

var combined = new Buffer(hash.length + salt.length + 8); 

然后我们将盐长度字节保存到位置0:

combined.writeUInt32BE(salt.length, 0, true);

我们保存迭代位置4(为什么4?):

combined.writeUInt32BE(config.iterations, 4, true);

我们将盐保存到位置8:

salt.copy(combined, 8);

我们将哈希值保存到位置,这是盐的长度加上我们保存迭代次数和盐长度的大小:

hash.copy(combined, salt.length + 8);

2 个答案:

答案 0 :(得分:2)

这段代码似乎正在制造一个现在危险的假设,即一个整数是4个字节长,因此两个整数是8个字节。"

在今天的64位世界中,这种假设将不再适用。而且,无论如何,我们都不需要这种复杂程度和字节错误!

更好的(并且,更简单)策略... (源代码示例未显示) ...只是将所有三个值存储为字符串,由已知字符分隔。例如,12:34:5678用于存储盐长度为12,迭代次数为34,哈希值为5678.存储该值的代码只是连接三个字符串并将它们存储在一个VARCHAR字段足够大。并且,以类似的方式,首先检索并检查值的代码"分裂"字符串分为三个组成部分(例如使用正则表达式...),将前两个字符串转换为整数,然后继续评估。

出于很多原因这是优选的,其中最重要的原因是查询数据库的人可以明显地看到这三个部分。 (因此,如果代码中存在某个错误,他/她可以看到错误的后果"一目了然。")

答案 1 :(得分:0)

使用库bcrypt,它很容易生成密码哈希。

安装&包括

npm install --save bcrypt

然后包括库

const bcrypt = require( 'bcrypt' );

生成&验证哈希

以异步方式生成散列使用以下方法。

bcrypt.hash( 'passwordToHash', 10, function( err, hash ) {
  // Store hash in database
});

10是生成salt时要使用的轮数。 验证密码

bcrypt.compare( 'passwordToCompare', hash, function( err, res ) {
  if( res ) {
   // Password matched
  } else {
   // Password didn't match
  } 
});

生成&验证哈希

以同步方式生成和验证哈希使用以下方法。

let hash = bcrypt.hashSync( 'passwordToHash', 10 );

10是生成salt时要使用的轮数。验证哈希

if( bcrypt.compareSync( 'passwordToCompare', hash ) ) {
   // Password matched
} else {
   // Password didn't match
}