【发布时间】:2016-10-06 10:39:23
【问题描述】:
上下文
在我当前的 Web 应用程序项目中,我设置了一个 MongoDB 数据库,包括服务器管理员和项目用户,通过使用 MongoDB shell 执行的一些 JavaScript 文件。
我似乎找不到以安全方式处理root 或用户密码的方法:
问题一:创建用户
这是我用来创建超级用户和项目用户的示例 JavaScript 文件:
use admin
db.createUser(
{
user: "root",
pwd: "abc123",
roles: [
{
role: "root",
db: "admin"
}]
})
use project_db
db.createUser(
{
user: "project_admin",
pwd: "def456",
roles: [
{
role: "dbOwner",
db: "project_db"
}]
})
显然,此文件受版本控制。我该如何不在其中存储明文密码?!? db.createUser(...) docs 明确声明必须传递明文密码(使用外部用户数据库时除外)。
说真的?!?
问题 2:使用凭据
我发现了三种在访问数据库时传递凭据的方法(例如运行数据库设置脚本);它们都不能令人满意:
在命令行上进行身份验证
mongo 可执行文件采用相应的参数:
mongo --username project_admin \
--password def456 \
--authenticationDatabase project_db \
< "${path_to_db_build_script}"
问题:密码在例如ps 输出。不可接受。
仅通过 --username project_admin 失败,Error: Missing expected field "pwd"。
传递 --username project_admin --password 使 mongo 以交互方式查询密码,这显然会阻止脚本自动执行 - 而 自动 这就是为什么这首先是一个脚本......
使用~/.mongorc.js进行身份验证
db = connect("localhost:27017/project_db");
db.getSiblingDB("project_db").auth("project_admin", "def456");
这确实有效,但似乎没有提供一种与多个用户一起工作的方法。可能有一种方法可以处理一个.js 文件每个用户 和/或.js 文件模板,但是一旦其中涉及任何复杂性,这些文件应该受到版本控制 - 并且让我们回到与创建用户相同的问题。
使用代码进行身份验证
理论上,也应该可以使用db.auth(...) 在脚本内进行身份验证。
在实践中,这对我来说似乎是一个史诗般的失败:
这可行,但将凭据存储在代码中:
db.auth("project_admin", "def456")
这可以使用 JSON 文档;还将凭据存储在代码中:
db.auth({ user: "project_admin", pwd: "def456" })
db.auth(...) 确实有一个 digestPassword 参数,该参数在很大程度上没有记录,但顾名思义,它旨在表明密码以某种加密/散列/加盐/任何方式传递。
这将允许使用非明文密码将.js 脚本存储在版本控制中;不理想,但绝对比明文更好。但是,这只是不起作用,即失败并显示Error: Authentication failed.
对于初学者,我假设在以明文形式传递密码时将digestPassword 设置为false 是合适的;但是,这失败了(BUG #1 ?):
db.auth({ user: "project_admin", pwd: "def456", digestPassword: fails })
而这有效(WTF ?!?):
db.auth({ user: "project_admin", pwd: "def456", digestPassword: true })
将mechanism 设置为PLAIN 失败并显示Error: Missing expected field "mechanism",尽管该字段明显存在(BUG #2 ?),无论digestPassword 是true 还是false:
db.auth({ user: "project_admin", pwd: "def456", digestPassword: true, mechanism: "PLAIN" })
将mechanism 设置为默认SCRAM-SHA-1 似乎暴露了与上述相同的错误;这失败了:
db.auth({ user: "project_admin", pwd: "def456", digestPassword: fails, mechanism: "SCRAM-SHA-1" })
这是可行的:
db.auth({ user: "project_admin", pwd: "def456", digestPassword: true, mechanism: "SCRAM-SHA-1" })
加密/散列/摘要/通过将mongo shell 启动为root 可以获得任何密码,例如
mongo admin -u root -p abc123
并运行db.system.users.find(),它会返回如下内容:
...
{
"_id": "project_db.project_admin",
"user": "project_admin",
"db": "project_db",
"credentials":
{
"SCRAM-SHA-1":
{
"iterationCount": 10000,
"salt": "WnKFmGs3BTbmkbUWi0RPnA==",
"storedKey": "EEIMqBEMUUOpoR3i3pgKz0iRumI=",
"serverKey": "HsSOxujNODlKcRiEdi1zkj83MRo="
}
},
"roles": [
{
"role": "dbOwner",
"db": "project_db"
}]
}
...
使用输出中的三个哈希 (?) 中的任何一个作为密码,digestPassword true 或 false 失败。在不查看来源的情况下,我只能假设 sha1(password + salt) 与上面的 credentials 有一些关系,但似乎没有任何文档,并且我迄今为止的尝试所暴露的假定错误并不完全鼓励追求这一点进一步。
自定义方法
可能有一种方法可以在 ~/.mongorc.js 中运行 JavaScript,它获取当前用户名(来自哪里?)并从外部来源查找密码。但是为什么我必须为假定的数据库解决方案实施凭据管理呢?
问题:
- 人们在使用 MongoDB 时如何处理凭据?
- 到目前为止,我对 MongoDB 的体验非常糟糕,考虑到 MongoDB 是为了生产目的而出售的,首先寻找我这边的原因似乎是明智之举。我在做一些根本错误的事情吗?我的期望不合理吗? MongoDB 用户不关心密码安全吗?
如果有人能分享他们的方法和经验,我将不胜感激。
【问题讨论】:
-
嗨@ssc,你找到方法了吗?这正是我目前正在寻找的东西,找不到任何东西。
-
@Lukino:不,抱歉。由于这个 - 以及许多其他问题 - 我停止尝试使用 MongoDB:我仍然觉得我从根本上误解了一些东西,但是 AFAICT,围绕 MongoDB 的炒作是不合理的;至少两年前我问这个问题的时候不是这样。
-
好吧,我设法破解了一点,所以 Mongo 设置并不是完全不安全的 - 主要是有明文密码......基本上你创建一个用户
db.createUser(...)使用假密码然后你以db.system.users.updateOne({user: "user", {$set: {credentials: "..."}}})的方式将他的凭据更新为已经散列的凭据。这不是完美的方法,但对我有用。这会让我不那么担心在 gitlab/chef 服务器上有未加密的密码(虽然对于后者有一个加密的数据包,我一直使用它,但我尽量不使用它)
标签: javascript mongodb authentication credentials