密码安全不是我的强项。请帮帮我。
我使用node.js 4.2.3 Express 4.13.3。我找到了一些使用 crypto 的 pbkdf2 对密码进行哈希和加盐的示例。
这是我的代码。
var salt = crypto.randomBytes(10).toString('base64');
console.log("salt > "+salt);
crypto.pbkdf2(pass, salt , 10000, 150, 'sha512',function(err, derivedKey) {
pass = derivedKey.toString('hex');
});
最终的导出 key 不包含盐。我缺少什么?我应该在保存之前手动连接两个字符串吗?
为什么有些示例使用 base64
而其他示例使用 hex
?获得不同的字符串长度?默认值是什么,我可以使用它吗?
为什么不在盐和哈希密码中使用 basic64
?
最终的衍生 key 字符串是UTF8吗?或者这仅与保存的数据库有关?我的数据库采用 UTF8 格式。
谢谢
最佳答案
是的,您自己单独存储盐,未加密。确保它是随机生成的。
更重要的是,您要求 150 字节(每个 nodejs.org 字节)的 key 长度来破坏 PBKDF2 加密 - SHA512 是一个绝佳的选择,但它只提供 64 字节的 native 输出。要获得 150 字节输出的 10,000 次迭代,PBKDF2/RFC2898将执行 30,000 次,而离线攻击者只需要运行 10,000 次迭代并匹配前 64 个字节(如果前 64 个字节匹配,则其余部分也将匹配); 你免费给了他们 3:1 的优势!
相反,如果您对工作因素感到满意,则应该使用 64 字节输出的 30,000 次迭代 - 您将花费相同的时间,没有区别,但攻击者现在也必须执行 30,000 次迭代,因此您夺走了他们 3:1 的优势!
当您将盐传递给 PBKDF2 函数时,如果可以的话,只需传递纯二进制文件即可。另外,node.js 文档合理地说“建议盐是随机的,并且它们的长度大于 16 个字节。”这意味着在进行 base64 或十六进制或任何您想要的转换之前,二进制 16 个字节。
您可以将 salt 和衍生 key 保存为正确长度的 BINARY,以实现最有效的存储(这样您就不必担心 UTF-x 与 ASCII),或者您可以将其中之一或两者转换为 BASE64 或十六进制,然后根据需要转换回二进制。只要根据需要重新转换转换,Base64、十六进制、二进制就无关紧要了。
我还将迭代次数作为存储字段,以便您可以在未来几年轻松增加它,并包含一个用于使用密码哈希“版本”的字段,以便您可以在未来几年轻松更改您的算法(如果需要)。
关于node.js - 使用 pbkdf2 crypto 哈希密码无法正常工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34459088/