Node 中密码存储的密码学最佳实践

Posted

技术标签:

【中文标题】Node 中密码存储的密码学最佳实践【英文标题】:Cryptography best practices for password storage in Node 【发布时间】:2014-12-18 14:04:26 【问题描述】:

我正在寻找一种使用 Node.js 存储用户密码的简单、安全的解决方案。我是密码学新手,但一直试图通过在线研究拼凑出一个解决方案。我正在寻找验证,我想出的是一个可靠的解决方案,适用于具有基本(而不是银行、医院等)安全需求的 Web 应用程序。这里是:

var crypto = require('crypto');
var SALT_LENGTH = 64;
var KEY_LENGTH = 64;
var ITERATIONS = 1000;

function createHashedPassword(plainTextPassword, cb) 
    crypto.randomBytes(SALT_LENGTH, function (err, salt) 
        console.time('password-hash');
        crypto.pbkdf2(plainTextPassword, salt, ITERATIONS, KEY_LENGTH, function (err, derivedKey) 
            console.timeEnd('password-hash');
            return cb(null, derivedKey: derivedKey, salt: salt, iterations: ITERATIONS);
        );
    );
;

...以下是我做出的选择让我走到了这一步:

使用什么哈希算法?

基于this widely referenced article,看起来领先的竞争者是 PBKDF2、bcrypt 和 scrypt。我选择了 PBKDF2,因为它在 Node 中内置了支持。

要使用什么大小的盐?

This stack overflow answer 似乎是我能找到的最直接的答案。我仍然不太清楚为什么 64 字节是正确的盐大小。当我四处搜索时,我得到了其他堆栈交换答案,例如this,但我不确定它是否适用于 Node 算法?在这里完全混淆了,针对使用此节点功能的新手的解释会很棒。

使用什么密钥长度?

再一次,我的选择主要基于the same answer as above,但我对“为什么”的基本知识同样模糊不清。答案是“生成小于输入的密钥是一种浪费,因此至少使用 64 个字节”。嗯?再一次,一个实用的解释会很有帮助。

要使用多少次迭代?

对于这个问题,我的选择基于this stack exchange answer。我不太了解,但我确实知道该算法应该花费大约 8 毫秒。因此,如您所见,我在函数上设置了计时器,并调整了迭代以使其在我的机器上处于该范围内。

谢谢!

【问题讨论】:

在安全性方面,通常最好坚持使用知名且经过良好测试的库。我想到了 Passport.JS,它有一些插件可以用来处理散列。 感谢@Pier-LucGendreau。我正在使用 PassportJS,但它不包含用于散列和存储密码的代码作为其库的一部分,或者它的子模块。如果我遗漏了什么,请告诉我。 你可以使用github.com/saintedlama/passport-local-mongoose 好的,我看了一下……但是,我看到上面提到的常量有更多看似随意的选择。他们选择 32 字节的默认 salt 长度、512 字节的密钥长度和 25000 次迭代。在我对以下答案的评论中:'credential' 节点包,创建者说“salt 的大小应该与哈希。不再更短,也不再“。这些实现之一是不正确的!这展示了我在研究过程中所看到的......我发现的每个实现都对这些常量使用不同的值,但没有解释为什么。 最重要的是,请记住,没有解决方案是防弹的。当今暴力破解的最佳解决方案是慢散列! 20 年前,您可以轻松地依赖 DES 或 RSA,而今天这些都不是安全的。它通过第三方验证层层叠加,即使那样你也只是挥手.... 【参考方案1】:

NPM 包credential 处理所有这些

你可以在Programming javascript Applications这本书里看到作者的写法

【讨论】:

我查看了这些链接,“凭据”包似乎在做与我上面相同类型的事情。在他的源代码中,他使用 66 字节的盐长度和密钥长度,以及 1000 次迭代的默认值。在包的自述文件中,他说“盐应该和散列一样大小。不再更短,也不再”。这些都是很好的信息,但我希望至少能看到“为什么”的基本解释? @markdb314 security.stackexchange.com 可能会更好地解释“为什么” 是的,我可能会在那里发帖......但答案通常比我能理解的更详细。我只是想找人自信地告诉我要使用哪些常量,以及一个简单的“为什么”。【参考方案2】:

我强烈推荐使用 BCrypt。该算法有很多优点,大多数实现都会为您处理所有这些问题。

如this answer中所述:

Bcrypt 拥有加密算法所能达到的最佳声誉:它已经存在了相当长的一段时间,被广泛使用,“引起了人们的关注”,但至今仍未被打破。

我在这里写了一篇关于如何在 node/express 以及其他框架中实现 BCrypt 的详细文章:http://davismj.me/blog/bcrypt

【讨论】:

以上是关于Node 中密码存储的密码学最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

存储和更新外部 API 密码的最佳实践

为小组存储生产密码的最佳实践

哈希密码的最佳实践

加盐密码:最佳实践? [关闭]

存储 oauth 和本地身份验证方法的最佳实践?

生成重置密码令牌的最佳实践