TLS/SSL 连接

Mongoose 支持连接到 需要 TLS/SSL 连接的 MongoDB 集群。在 mongoose.connect() 或您的连接字符串中将 tls 选项设置为 true 就足以使用 TLS/SSL 连接到 MongoDB 集群。

mongoose.connect('mongodb://127.0.0.1:27017/test', { tls: true });

// Equivalent:
mongoose.connect('mongodb://127.0.0.1:27017/test?tls=true');

对于以 mongodb:// 开头的连接字符串,tls 选项默认值为 false。但是,对于以 mongodb+srv:// 开头的连接字符串,tls 选项默认值为 true。因此,如果您使用 srv 连接字符串连接到 MongoDB Atlas,则默认情况下会启用 TLS/SSL。

如果您尝试连接到需要 TLS/SSL 但未启用 tls/ssl 选项的 MongoDB 集群,mongoose.connect() 将出现以下错误

MongooseServerSelectionError: connectionto 127.0.0.1:27017 closed at NativeConnection.Connection.openUri (/node_modules/mongoose/lib/connection.js:800:32) ...

TLS/SSL 验证

默认情况下,Mongoose 会将 TLS/SSL 证书与 证书颁发机构 进行验证,以确保 TLS/SSL 证书有效。要禁用此验证,请将 tlsAllowInvalidCertificates(或 tlsInsecure)选项设置为 true

mongoose.connect('mongodb://127.0.0.1:27017/test', {
  tls: true,
  tlsAllowInvalidCertificates: true,
});

在大多数情况下,您不应在生产环境中禁用 TLS/SSL 验证。但是,tlsAllowInvalidCertificates: true 通常有助于调试 SSL 连接问题。如果您可以在 tlsAllowInvalidCertificates: true 的情况下连接到 MongoDB,但在 tlsAllowInvalidCertificates: false 的情况下无法连接,那么您可以确认 Mongoose 可以连接到服务器,并且服务器已正确配置为使用 TLS/SSL,但证书存在一些问题。

例如,常见的错误消息如下

MongooseServerSelectionError: unable to verify the first certificate

此错误通常是由 自签名 MongoDB 证书 或其他情况导致的,在这种情况下,MongoDB 服务器发送的证书未在已建立的证书颁发机构中注册。解决办法是设置 tlsCAFile 选项,它实际上设置了允许的 SSL 证书列表。

await mongoose.connect('mongodb://127.0.0.1:27017/test', {
  tls: true,
  // For example, see https://medium.com/@rajanmaharjan/secure-your-mongodb-connections-ssl-tls-92e2addb3c89
  // for where the `rootCA.pem` file comes from.
  tlsCAFile: `${__dirname}/rootCA.pem`,
});

另一个常见的问题是以下错误消息

MongooseServerSelectionError: Hostname/IP does not match certificate's altnames: Host: hostname1. is not cert's CN: hostname2

SSL 证书的 通用名称 **必须** 与您的连接字符串中的主机名一致。如果 SSL 证书用于 hostname2.mydomain.com,则您的连接字符串必须连接到 hostname2.mydomain.com,而不是任何其他主机名或 IP 地址,这些主机名或 IP 地址可能等效于 hostname2.mydomain.com。对于副本集,这也意味着 SSL 证书的通用名称必须与 机器的 hostname 一致。要禁用此验证,请将 tlsAllowInvalidHostnames 选项设置为 true

X.509 身份验证

如果您使用的是 X.509 身份验证,则应在连接字符串中设置用户名,**而不是** connect() 选项。

// Do this:
const username = 'myusername';
await mongoose.connect(`mongodb://${encodeURIComponent(username)}@127.0.0.1:27017/test`, {
  tls: true,
  tlsCAFile: `${__dirname}/rootCA.pem`,
  authMechanism: 'MONGODB-X509',
});

// Not this:
await mongoose.connect('mongodb://127.0.0.1:27017/test', {
  tls: true,
  tlsCAFile: `${__dirname}/rootCA.pem`,
  authMechanism: 'MONGODB-X509',
  auth: { username },
});

使用 MongoDB Atlas 的 X.509 身份验证

对于 MongoDB Atlas,X.509 证书不是根 CA 证书,并且与自签名证书一样,不会与 tlsCAFile 参数一起使用。如果使用 tlsCAFile 参数,则会引发类似于以下内容的错误

MongoServerSelectionError: unable to get local issuer certificate

要使用 X.509 身份验证连接到 MongoDB Atlas 集群,要设置的正确选项是 tlsCertificateKeyFile。连接字符串已经指定了 authSourceauthMechanism,但是为了完整性,它们包含在下面的 connect() 选项中。

const url = 'mongodb+srv://xyz.mongodb.net/test?authSource=%24external&authMechanism=MONGODB-X509';
await mongoose.connect(url, {
  tls: true,
  // location of a local .pem file that contains both the client's certificate and key
  tlsCertificateKeyFile: '/path/to/certificate.pem',
  authMechanism: 'MONGODB-X509',
  authSource: '$external',
});

注意 连接字符串选项必须正确 URL 编码。