如何将用户密码安全地存储在 Cloudant 数据库中?

How to securely store user passwords in a Cloudant DB?

您应该如何将用户密码存储在 Cloudant 数据库中?我所说的用户是指使用 Cloudant 作为后端的应用程序的用户。

我搜索了文档,但没有找到任何关于该主题的内容。 有一个 _users 数据库,您可以在其中创建用户并添加一个 "password" 字段,但密码是数据库管理员(可能还有其他人)可以读取的常规字段。

是否有内置方法可以隐藏或加密它?

编辑

我找到了一块拼图,CouchDB security feature 用于加密用户密码。

Since CouchDB 1.2.0, the password_sha and salt fields are automatically created when a password field is present in the user document. When the user document is written, CouchDB checks for the existence of the password field and if it exists, it will generate a salt, hash the value of the password field and hash the concatenation of the password hash and the salt. It then writes the resulting password into the password_sha field and the salt into the salt field. The password field is removed.

This has the following implications: Clients no longer have to calculate the password salt and hash manually. Yay.

现在缺少的是底层数据库功能和 Cloudant 之间的 link(仅在用户文档中设置 password 字段不起作用)。

编辑 2

发现 与此类似 - 这是一个更广泛的问题,但专门针对网络应用程序。 @JasonSmith 提供了一个公认的答案来解决我的问题:

Can I use CouchDB security features

答案"yes you can"

Cloudant does not yet have the newer CouchDB feature where the server will automatically hash the password for you

但 CouchDB 文档指出此功能包含在 2013 年的 1.20 版本中! "newer" 功能如何?

从文档中,我得知 Cloudant 使用 CouchDB 1.61。

回顾一下:

所以...失踪的link真的真的小...

首先,您真的非常需要阅读 Thomas Pornin's canonical answer to How to Securely Hash Passwords

立即阅读。

现在阅读 CouchDB link,并查看为 1.3 生成 password_sha 的推荐方法之一(如果您至少没有使用 1.3,请到那里)。

{ "_id": "org.couchdb.user:username", "_rev": "1-227bbe6ddc1db6826fb6f8a250ef6264", "password_scheme": "pbkdf2", "iterations": 10, "name": "username", "roles": [ ], "type": "user", "derived_key": "aa7dc3719f9c48f1ac72754b28b3f2b6974c2062", "salt": "77bac623e30d91809eecbc974aecf807" }

确保 password_scheme 是 pbkdf2!

看到"iterations":10个一样吗?你需要 bump that up by a huge amount - 我会说尝试一个低至数十万的数字,看看它是如何运行的; SHA-1 现在很便宜。

就 Cloudant 而言,here's a Github repository 使用一些代码让 Cloudant 使用 CouchDB _users。

如您所见,Cloudant 不会像 Couch 1.2 中引入的那样自动对服务器端密码进行哈希处理。此外,它只支持简单的密码方案:salted SHA1(您可能会觉得不够用)。这就是应该保存密码的方式(不是纯文本)。

它还缺少许多其他安全功能,例如 _users 数据库的特殊访问规则(here 描述)。

散列密码 "automatically" 可以通过更新函数完成(特殊访问规则可以通过 show/list 函数实现)。我自己做过:

function (doc, req) {

    var body = JSON.parse(req.body || '{}') || {};

    if (doc == null) doc = {
        _id: req.id,
        type: 'user'
    };

    doc.name = body.name;
    doc.roles = body.roles;
    doc.salt = req.uuid;
    doc.password_scheme = 'simple';
    doc.password_sha = hex_sha1(body.password + doc.salt);

    return [doc, { json: doc }];
}

here. Set the above as an update function in a design doc on the _users database. You can also use this as a validation function 得到 hex_sha1

然后不是将用户放入数据库,而是将相同的 JSON 放入更新函数,它会在将其提交到数据库之前生成加盐哈希。

如果加盐 SHA1 不足以满足您的目的,您不能像现在一样依赖 _users Cloudant。


对你的设计了解不多,我真的不能给太多建议。

但我应该警告你,由于 _users 支持不佳,例如在 Cloudant 上有效地实现 2 层架构几乎是不可能的。我很高兴被更了解的人反驳,但在我几个月来一直反对这个问题(和唠叨的支持)之后,这就是我得出的结论。

最终,您需要一个应用层来进行用户管理,通过 _users 或 API 键。一旦你有了这样一个层,你就可以在那里散列密码,and/or 跳过 _users 数据库并以其他方式进行用户管理。一旦事情变得足够复杂,Cloudant 发布的每个示例最终都会这样做(顺便说一句,none 的示例扩展到数万用户)。


最后,@Anti-weakpasswords,他说你必须使用 PBKDF2 和巨大的迭代次数。

这是关于一般保存密码的合理建议,但是:

  1. 这根本不适用于 Cloudant;
  2. 它与 CouchDB 的配合也不是很好。

首先,如前所述,如果加盐 SHA1 是 Cloudant 所支持的全部内容,句号。

但即使对于 CouchDB,这也是一个糟糕的建议。使用基本的 HTTP 身份验证,您将在每个请求中发送密码。对每个请求进行大量迭代计数的键拉伸会给服务器带来巨大压力,因此不建议进行大量迭代计数(这就是文档中有 10 的原因)。如果你要走那条路,你需要确保你总是使用 _session 和 cookies,并避免像瘟疫一样的基本身份验证。

更有可能的是,如果您认真对待安全性,您需要在客户端和数据库之间建立一个层以其他方式处理用户管理,并使用足够强的密码解耦数据库 users/roles 不需要完全是强哈希。

Clusers刚出来!它可能对你有用。 Clusers 是用于 Cloudant 和 CouchDB 的用户帐户创建器。它使用较旧的 "password_scheme: simple" Cloudant 和较旧的 CouchDB。