MongoDB:如何安全地存储凭证?

ssc*_*ssc 10 javascript authentication credentials mongodb

上下文

在我当前的Web应用程序项目中,我通过使用MongoDB shell执行的许多JavaScript文件来设置MongoDB数据库,包括服务器管理员和项目用户.

我似乎找不到以安全的方式处理root或使用密码的方法:

问题1:创建用户

这是我用来创建超级用户和项目用户的示例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"
    }]
})
Run Code Online (Sandbox Code Playgroud)

显然,此文件受版本控制.我怎么不在那里存储明文密码?!?该db.createUser(...)文档明确地陈述明文口令必须被传递(使用外部用户数据库时除外).

说真的?!?

问题2:使用凭据

我在访问数据库时找到了三种传递凭证的方法(例如运行数据库设置脚本); 它们都没有令人满意地工作:

在命令行上进行身份验证

mongo可执行文件采取相应的参数:

mongo --username project_admin            \
      --password def456                   \
      --authenticationDatabase project_db \
    < "${path_to_db_build_script}"
Run Code Online (Sandbox Code Playgroud)

问题:密码在例如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");
Run Code Online (Sandbox Code Playgroud)

这确实有效,但似乎没有提供与多个用户合作的方法.可能有一种方法可以处理每个用户和/或文件模板的一个.js文件,但是一旦涉及任何复杂性,这些文件应该受版本控制 - 这使我们回到与创建用户相同的问题..js

使用代码进行身份验证

理论上,还应该可以使用db.auth(...)脚本中的身份验证.
在实践中,这对我来说似乎是一个史诗般的失败:

这有效,但在代码中存储凭据:

db.auth("project_admin", "def456")
Run Code Online (Sandbox Code Playgroud)

这适用于使用JSON doc; 还将凭证存储在代码中:

db.auth({ user: "project_admin", pwd: "def456" })
Run Code Online (Sandbox Code Playgroud)

db.auth(...)确实有一个digestPassword很大程度上没有记录的参数,但顾名思义它表示密码以一些加密/散列/盐渍/任何方式传递.

这将允许.js使用非明文密码将脚本存储在版本控制中; 不理想,但肯定比明文更好.但是,这根本不起作用,即失败了Error: Authentication failed.

对于初学者来说,我会假设设置digestPasswordfalse明文传递密码的时候是合适的; 但是,这失败了(BUG#1?):

db.auth({ user: "project_admin", pwd: "def456", digestPassword: fails })
Run Code Online (Sandbox Code Playgroud)

这是有效的(WTF?!?):

db.auth({ user: "project_admin", pwd: "def456", digestPassword: true })
Run Code Online (Sandbox Code Playgroud)

设置mechanismPLAIN失败Error: Missing expected field "mechanism",尽管该领域显然是有(BUG#2?),如果不管digestPasswordtruefalse:

db.auth({ user: "project_admin", pwd: "def456", digestPassword: true, mechanism: "PLAIN" })
Run Code Online (Sandbox Code Playgroud)

设置mechanism为默认值SCRAM-SHA-1似乎暴露了与上面相同的错误; 这失败了:

db.auth({ user: "project_admin", pwd: "def456", digestPassword: fails, mechanism: "SCRAM-SHA-1" })
Run Code Online (Sandbox Code Playgroud)

这有效:

db.auth({ user: "project_admin", pwd: "def456", digestPassword: true, mechanism: "SCRAM-SHA-1" })
Run Code Online (Sandbox Code Playgroud)

加密/散列/消化/可以通过启动mongoshell 获得任何密码root,例如

mongo admin -u root -p abc123
Run Code Online (Sandbox Code Playgroud)

和运行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"
    }]
}
  ...
Run Code Online (Sandbox Code Playgroud)

使用输出中的三个哈希(?)中的任何一个作为密码digestPassword true或使用密码false.在没有查看来源的情况下,我只能假设sha1(password + salt)credentials上述有一些关系,但似乎没有任何文档,而且我迄今为止所尝试的假定错误并不完全鼓励进一步追求这一点.

定制方法

可能有一种方法可以运行JavaScript ~/.mongorc.js,使用当前用户名(从哪里?)并从外部源查找密码.但为什么我必须为假定的数据库解决方案实现凭据管理?

问题:

  1. 在使用MongoDB时,人们如何处理凭据?
  2. 到目前为止,我对MongoDB的体验非常糟糕,因为考虑到MongoDB是出于生产目的而出售的,首先在我身边寻找原因似乎是明智之举.我做了一些根本错误的事吗?我的期望是不合理的吗?MongoDB用户不关心密码安全吗?

如果有人可以分享他们的方法和经验,我将不胜感激.

sat*_*ati -5

我假设你正在使用node.js

\n\n

因此基本方法是进行应用程序端加密,即在将其保存到 mongoDB 之前在应用程序代码中加密密码等字段。

\n\n

你怎么做的?

\n\n

你可以使用名为的node.js包bcrypt

\n\n

要安装 bcrypt,请使用以下命令:npm install bcrypt \xe2\x80\x93save-dev.

\n\n

然后,您可以在保存操作上编写一个函数,该函数将在将所需字段保存到 MongoDatabase 之前对其进行加密。

\n\n
var mongoose = require(\'mongoose\');\nvar bcrypt = require(\'bcrypt\');\nvar SALT_WORK_FACTOR = 10;\nmongoose.connect(\'mongodb://localhost/project_db\');\n\nvar db = mongoose.connection;\n\ndb.on(\'error\', function(err){\n    console.log(\'connection error\', err);\n});\n\ndb.once(\'open\', function(){\n    console.log(\'Connection to DB successful\');\n});\n\nvar Schema = mongoose.Schema;\nvar userSchema= new Schema({\n    name:String,\n    password:String\n});\n\nvar User = mongoose.model(\'User\', userSchema);\n\nuserSchema.pre(\'save\', function(next){\n    var user = this;\n    if (!user.isModified(\'password\')) return next();\n\n    bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt){\n        if(err) return next(err);\n\n        bcrypt.hash(user.password, salt, function(err, hash){\n            if(err) return next(err);\n\n            user.password = hash;\n            next();\n        });\n    });\n});\n\nvar testSample = new  User({\n    name: "admin",\n   password: "password1234"\n});\n\ntestSample.save(function(err, data){\n    if(err) console.log(err);\n    else console.log (\'Sucess:\' , data);\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

您的另一个选择是在数据库级别本身配置一些安全性。嗯,这是一件大事,所以我无法在这里总结它。

\n\n

希望这个链接对您有帮助:https ://docs.mongodb.com/manual/security/

\n