使用Node.js通过SSL连接到MongoDB

Connecting to MongoDB over SSL with Node.js

本文关键字:连接 MongoDB SSL 通过 Node js 使用      更新时间:2023-09-26

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

我已经阅读了一些驱动程序的源代码(mongojs, mongodb-native),我已经搜索了一段时间,但似乎找不到任何合适的教程,指南或文档。

步骤1:获取MongoDB 3.0

您需要知道的第一件事是,SSL只支持MongoDB 3.0及更高版本的开箱即用。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"为私钥文件,"mongodb-cert. key"为私钥文件。crt为证书文件,也可以作为CA文件使用。这三个你都需要。

步骤3:配置MongoD

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

sudo vi /etc/mongod.conf

和修改"#网络接口"段落如下:

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

PLEASE NOTE:我们正在注释掉bindIp。这允许外部连接访问你的Mongo数据库。我们假设这是您的最终目标(为什么要加密本地主机上的流量?),但是您应该只在为您的MongoDB服务器设置授权规则后才这样做。

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

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

sudo service mongod restart
你的服务器启动失败了吗?您可以自行解决问题,但是您的证书文件可能有问题。您可以通过手动运行mongod来检查启动错误:
sudo mongod --config /etc/mongod.conf

步骤4:测试服务器设置

在我们开始搞乱Node配置之前,让我们通过连接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 (或bundle)文件。这看起来很像您的证书文件,但通常包含多个证书(形成一个信任链,以验证证书是否有效)。如果您使用的是自签名证书,则可以使用mongodb-cert.crt作为CA文件。

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

步骤6.3:更新mongod配置

sudo vi /etc/mongod.conf

和修改"#网络接口"段落如下:

# 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库。*不提供此选项。在节点4中。*和5。*,有一个checkServerIdentity选项提供了希望,但从原来的Node分支切换到io.js合并后的分支,目前可能会引起一些头痛。

那么我们试试这个:

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')
      }
    }
  ;

来源

正如评论中建议的那样,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 }})

如果您想使用证书进行身份验证,请使用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();
});