Node.js中的密码哈希

Node.js中的密码哈希,node.js,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 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是否可以接受?我很久以前就发现了这个算法,现在我不确定我是否理解得很好

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

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

combined.writeUInt32BE(salt.length, 0, true);
我们保存迭代位置4(为什么是4?):

我们将盐保存到位置8:

salt.copy(combined, 8);
我们将哈希保存到位置,即salt的长度加上保存迭代的大小和salt的长度:

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

这段代码似乎做出了一个危险的假设:“一个整数的长度为4字节,因此两个整数的长度为8字节。”

在今天的64位世界中,这一假设不再成立。而且,在任何情况下,我们都不需要这种复杂程度和字节旋转

一个更好(更简单)的策略。。。(未显示源代码示例)。。。就是将所有三个值存储为字符串,由一个已知字符分隔。例如,
12:34:5678
用于存储salt长度12,迭代次数34,散列值5678。存储值的代码只是将三个字符串串联起来,并将它们存储在足够大的
VARCHAR
字段中。并且,以类似的方式,首先检索和检查值的代码将字符串“拆分”为其三个组成部分(例如,使用正则表达式…),将前两个字符串转换为整数,并继续计算

出于许多原因,这是比较可取的,尤其是查询数据库的人可以清楚地看到这三个部分。(因此,如果代码中的某个地方有bug,他/她可以“一目了然”地看到bug的后果。)

使用库很容易生成密码散列

安装并包括 然后包括图书馆

const bcrypt = require( 'bcrypt' );
生成并验证哈希 要以异步方式生成哈希,请使用以下方法

bcrypt.hash( 'passwordToHash', 10, function( err, hash ) {
  // Store hash in database
});
let hash = bcrypt.hashSync( 'passwordToHash', 10 );
10
是生成盐时使用的轮数。 验证密码

bcrypt.compare( 'passwordToCompare', hash, function( err, res ) {
  if( res ) {
   // Password matched
  } else {
   // Password didn't match
  } 
});
生成并验证哈希 要以同步方式生成和验证哈希,请使用以下方法

bcrypt.hash( 'passwordToHash', 10, function( err, hash ) {
  // Store hash in database
});
let hash = bcrypt.hashSync( 'passwordToHash', 10 );
10
是生成盐时使用的轮数。验证散列

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

不是密码加密领域的专家。你有没有研究过使用他人的加密库而不是编写自己的加密库的可能性?我同意,并将添加一个版本指示器作为第一项,特别是有不同版本的PBKDF2使用不同的哈希函数,未来的校对似乎是一件好事..似乎很好。(事实上,“非常好的建议。”数据库条目可以永久保存,(感谢上帝,现在…)存储很便宜。你有足够的空间让你的记录“自我描述”谢谢@MikeRobinson,您是否建议我也将salt存储为该条目的一部分,如下所示:
salt\u length:salt\u value:iterations:hash
?salt值通常存储为字符串的一部分,正如您所示。以字符形式,由一个字符分隔,您可以轻松地
拆分()
by。我不确定您是否需要
salt\u length
,因为您的
salt\u值就在那里。但是,在任何情况下,我想在前面添加一个固定的数字…一个
算法
数字,如果您愿意的话…它可以简单地识别(始终)计算此散列的方法。如果或某个后继者以后做了一些不同的操作,您所要做的就是更新该代码。每个散列字符串“自我标识”它是如何生成的。
if( bcrypt.compareSync( 'passwordToCompare', hash ) ) {
   // Password matched
} else {
   // Password didn't match
}