【问题标题】:Connecting to MongoDB over SSL with Node.js使用 Node.js 通过 SSL 连接到 MongoDB
【发布时间】:2014-08-14 09:59:29
【问题描述】:

如何使用 Node.js 通过 SSL 连接到 MongoDB 服务器?

我已经阅读了一些驱动程序的来源(mongojsmongodb-native)并且我已经在谷歌上搜索了一段时间,但似乎找不到任何合适的教程、指南或文档。

【问题讨论】:

  • mongodb ssl node.js 的第二个结果可能会让您感兴趣 mongodb.github.io/node-mongodb-native/api-generated/server.html
  • 嗯.. 我开始玩弄这个,但没有让它工作。我会再试一次。
  • 还有投票关闭的版主:真的吗?这与编程无关?让我们永远不要编写连接到数据库的代码。
  • 后来问另一个问题时肯定是重复的......愚蠢的我发布了一个新问题,而这个问题将在 7 个月后被别人问到! :)

标签: javascript node.js mongodb ssl


【解决方案1】:

第一步:获取MongoDB 3.0

您需要知道的第一件事是,只有 MongoDB 3.0 及更高版本开箱即用地支持 SSL。 Ubuntu 在默认存储库中没有 3.0,因此您可以通过以下方式获取它:

sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 7F0CEB10
echo "deb http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.0.list
sudo apt-get update
sudo apt-get install -y mongodb-org=3.0.7 mongodb-org-server=3.0.7 mongodb-org-shell=3.0.7 mongodb-org-mongos=3.0.7 mongodb-org-tools=3.0.7

3.0.7 是目前最新的稳定版本,但您可以随意将 3.0.7 替换为您最喜欢的版本。

第 2 步:获取私钥、证书和 PEM 文件

PEM 包含一个公钥证书及其关联的私钥。这些文件可以使用 IRL 美元从证书授权机构获得,也可以使用 OpenSSL 生成,如下所示:

openssl req -newkey rsa:2048 -new -x509 -days 3650 -nodes -out mongodb-cert.crt -keyout mongodb-cert.key
cat mongodb-cert.key mongodb-cert.crt > mongodb.pem

mongodb.pem 将用作 PEM 文件,mongodb-cert.key 是 Private Key 文件,mongodb-cert.crt 是证书文件,也可以用作 CA 文件。您将需要所有这三个。

第 3 步:配置 MongoD

我们将假设您已将这些文件复制到它们所属的 /etc/ssl/ 文件夹中。现在我们打开 MongoDB 配置文件:

sudo vi /etc/mongod.conf

并像这样修改“# network interfaces”部分:

# network interfaces
net:
  port: 27017
  #bindIp: 127.0.0.1
  ssl:
    mode: allowSSL
    PEMKeyFile: /etc/ssl/mongodb.pem
    #CAFile: /etc/ssl/mongodb-cert.crt

请注意:我们正在注释掉bindIp。这允许外部连接访问您的 Mongo 数据库。我们假设这是您的最终目标(为什么要在 localhost 上加密流量?),但您应该只在为您的 MongoDB 服务器设置授权规则之后执行此操作。

CAFile 也被注释掉,因为它是可选的。我将在本文末尾解释如何设置证书颁发机构信任。

与往常一样,您必须重新启动 MongoDB,配置文件更改才会生效:

sudo service mongod restart

您的服务器无法启动吗?您是一个人,但您的证书文件可能存在问题。您可以通过手动运行mongod 来检查启动错误:

sudo mongod --config /etc/mongod.conf

第 4 步:测试您的服务器设置

在我们搞乱节点配置之前,让我们通过连接mongo 命令行客户端来确保您的服务器设置正常工作:

mongo --ssl --sslAllowInvalidHostnames --sslAllowInvalidCertificates

除非您证书上的域名是127.0.0.1localhost,否则--sslAllowInvalidHostnames 标志是必需的。没有它,你可能会得到这个错误:

E NETWORK  The server certificate does not match the host name 127.0.0.1
E QUERY    Error: socket exception [CONNECT_ERROR] for 
    at connect (src/mongo/shell/mongo.js:179:14)
    at (connect):1:6 at src/mongo/shell/mongo.js:179
exception: connect failed

第 5 步:配置 Node.JS / Mongoose

如果您在 Node 应用程序中使用 node-mongodb-native 包,请立即停止并开始使用 Mongoose。这并不难。也就是说,mongoose.connect()mongodb.connect() 具有几乎相同的 API,因此请适当替换。

    var fs = require('fs')
      , mongoose = require('mongoose')
      , mongoUri = "mongodb://127.0.0.1:27017?ssl=true"
      , mongoOpt = {
          "sslValidate": false,
          "sslKey": fs.readFileSync('/etc/ssl/mongodb.pem'),
          "sslCert": fs.readFileSync('/etc/ssl/mongodb-cert.crt')
        }
      ;

mongoose.connect(mongoUri, mongoOpt);

第 6 步:[可选] 通过证书颁发机构验证您的证书

为了验证您的 SSL 证书,您需要从您的证书颁发机构获取 CA( 或捆绑)文件。这看起来很像您的证书文件,但通常包含多个证书(形成一个信任链来验证证书是否有效)。如果您使用的是自签名证书,则可以将 mongodb-cert.crt 用作 CA 文件。

您还需要确保 MongoDB 服务器的主机名与用于创建证书的主机名匹配。

步骤 6.3:更新您的 mongod 配置

sudo vi /etc/mongod.conf

并像这样修改“# network interfaces”部分:

# network interfaces net:   port: 27017   #bindIp: 127.0.0.1   ssl:
    mode: allowSSL
    PEMKeyFile: /etc/ssl/mongodb.pem
    CAFile: /etc/ssl/mongodb-ca.crt

sudo service mongod restart

步骤 6.4:测试您的服务器设置

mongo --ssl --sslAllowInvalidHostnames --sslCAFile /etc/ssl/mongodb-ca.crt --sslPEMKeyFile /etc/ssl/mongodb.pem

Mongo 客户端也可以传入 CA 文件,以验证它们正在与正确的服务器通信。这是通过--sslCAFile 参数完成的

配置了 CAFile 的 Mongo 服务器要求客户端拥有有效的证书服务器的私钥。在 mongo shell 客户端中,这是通过传入--sslPEMKeyFile 参数来完成的。

如果没有 PEM 文件(包含服务器的证书),您可能会看到以下错误:

I NETWORK  DBClientCursor::init call() failed
E QUERY    Error: DBClientBase::findN: transport error: 127.0.0.1:27017 ns: admin.$cmd query: { whatsmyuri: 1 }
    at connect (src/mongo/shell/mongo.js:179:14)
    at (connect):1:6 at src/mongo/shell/mongo.js:179
exception: connect failed

通过启用net.ssl.weakCertificateValidation,可以将服务器配置为接受来自没有 PEM 文件的客户端的请求,但您会削弱安全性而没有真正的收获。

步骤 6.5:配置 Node.JS / Mongoose

这里有几个问题,请耐心等待。

首先,您需要拥有node-mongodb-native 2.0 或更高版本。如果您使用的是 Mongoose,那么您需要 Mongoose 4.0 或更高版本。以前的 Mongoose 版本使用 node-mongodb-native 1.*,它不支持任何容量的证书验证。

其次,在 node-mongodb-native 中没有sslAllowInvalidHostnames 或类似选项可用。这不是node-mongodb-native 开发人员可以解决的问题(我现在应该有),因为 Node 0.10.* 中可用的本机 TLS 库没有为此提供任何选项。在 Node 4.* 和 5.* 中,有一个 checkServerIdentity 选项提供了希望,但是在 io.js 合并后从原始 Node 分支切换到分支可能会在当前时间引起一些头痛。

让我们试试这个:

var fs = require('fs')
  , mongoose = require('mongoose')
  , mongoUri = "mongodb://127.0.0.1:27017?ssl=true"
  , mongoOpt = {
      "server": { 
        "sslKey": fs.readFileSync('/etc/ssl/mongodb.pem'),
        "sslCert": fs.readFileSync('/etc/ssl/mongodb-cert.crt'),
        "sslCa": fs.readFileSync('/etc/ssl/mongodb-ca.crt')
      }
    }
  ;

如果您遇到主机名/IP 不匹配错误,请修复您的证书,或者通过禁用 sslValidate 来消除所有这些辛苦工作:

var fs = require('fs')
  , mongoose = require('mongoose')
  , mongoUri = "mongodb://127.0.0.1:27017?ssl=true"
  , mongoOpt = {
      "server": {
        "sslValidate": false,
        "sslKey": fs.readFileSync('/etc/ssl/mongodb.pem'),
        "sslCert": fs.readFileSync('/etc/ssl/mongodb-cert.crt'),
        "sslCa": fs.readFileSync('/etc/ssl/mongodb-ca.crt')
      }
    }
  ;

Source

【讨论】:

  • 查看我对您的duplicate answer 的评论。这里同样适用。
  • 很棒的答案,非常感谢您提供非常详细的步骤!
【解决方案2】:

根据 cmets 的建议,node-mongodb-native 拥有所需的一切。

我使用以下方法启动并运行它:

var mongo = require('mongodb');

var server = new mongo.Server('HOSTNAME', 27017, { ssl: true });
var db = new mongo.Db('NAME_OF_MY_DB', server, { w: 1 });
var auth = { user: 'USERNAME', pass: 'PASSWORD' };

db.open(function(err, db) {
  if (err) return console.log("error opening", err);

  db.authenticate(auth.user, auth.pass, function(err, result) {
    if (err) return console.log("error authenticating", err);

    console.log("authed?", result);

    db.collection('whatever').count(function(err, count) {
      if (err) return console.log("error counting", err);

      console.log("count", count);
      db.close()
    });
  });
});

编辑

你也可以从mongoose做ssl:

mongoose.createConnection(connString, { server: { ssl: true }})

【讨论】:

  • 为什么没有指定 sslCA、sslCert 和 sslKey?
【解决方案3】:

如果要使用证书进行身份验证,请使用node-mongodb-native

var buffer = require('fs').readFileSync("mongodb.pem");
var MongoClient = require('mongodb').MongoClient;
MongoClient.connect("mongodb://hostname:27017/test?ssl=true", {
    sslKey: buffer,
    sslCert: buffer,
    sslValidate: false //in case of self-generated certificate
}, function(err, db) {
    console.log(err);
    console.log(db);
    db.close();
});

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-15
    • 2019-07-05
    • 2016-05-28
    • 2020-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多