TLS/SSL 连接

¥TLS/SSL Connections

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

¥Mongoose supports connecting to MongoDB clusters that require TLS/SSL connections. Setting the tls option to true in mongoose.connect() or your connection string is enough to connect to a MongoDB cluster using TLS/SSL:

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 阿特拉斯,则默认启用 TLS/SSL。

¥The tls option defaults to false for connection strings that start with mongodb://. However, the tls option defaults to true for connection strings that start with mongodb+srv://. So if you are using an srv connection string to connect to MongoDB Atlas, TLS/SSL is enabled by default.

如果你尝试连接到需要 TLS/SSL 的 MongoDB 集群而不启用 tls/ssl 选项,mongoose.connect() 将出错并显示以下错误:

¥If you try to connect to a MongoDB cluster that requires TLS/SSL without enabling the tls/ssl option, mongoose.connect() will error out with the below error:

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

TLS/SSL 验证

¥TLS/SSL Validation

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

¥By default, Mongoose validates the TLS/SSL certificate against a certificate authority to ensure the TLS/SSL certificate is valid. To disable this validation, set the tlsAllowInvalidCertificates (or tlsInsecure) option to 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,但证书存在一些问题。

¥In most cases, you should not disable TLS/SSL validation in production. However, tlsAllowInvalidCertificates: true is often helpful for debugging SSL connection issues. If you can connect to MongoDB with tlsAllowInvalidCertificates: true, but not with tlsAllowInvalidCertificates: false, then you can confirm Mongoose can connect to the server and the server is configured to use TLS/SSL correctly, but there's some issue with the certificate.

例如,一个常见问题是以下错误消息:

¥For example, a common issue is the below error message:

MongooseServerSelectionError: unable to verify the first certificate

此错误通常是由于 自签名 MongoDB 证书 或 MongoDB 服务器发送的证书未向已建立的证书颁发机构注册的其他情况导致的。解决方案是设置 tlsCAFile 选项,该选项实质上设置允许的 SSL 证书列表。

¥This error is often caused by self-signed MongoDB certificates or other situations where the certificate sent by the MongoDB server is not registered with an established certificate authority. The solution is to set the tlsCAFile option, which essentially sets a list of allowed SSL certificates.

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`,
});

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

¥Another common issue is the below error message:

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,而不是可能相当于 hostname2.mydomain.com 的任何其他主机名或 IP 地址。对于副本集,这也意味着 SSL 证书的公用名称必须与 机器的 hostname 一致。要禁用此验证,请将 tlsAllowInvalidHostnames 选项设置为 true

¥The SSL certificate's common name must line up with the host name in your connection string. If the SSL certificate is for hostname2.mydomain.com, your connection string must connect to hostname2.mydomain.com, not any other hostname or IP address that may be equivalent to hostname2.mydomain.com. For replica sets, this also means that the SSL certificate's common name must line up with the machine's hostname. To disable this validation, set the tlsAllowInvalidHostnames option to true.

X.509 认证

¥X.509 Authentication

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

¥If you're using X.509 authentication, you should set the user name in the connection string, not the connect() options.

// 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 身份验证

¥X.509 Authentication with MongoDB Atlas

对于 MongoDB Atlas,X.509 证书不是根 CA 证书,并且不能像自签名证书那样与 tlsCAFile 参数配合使用。如果使用 tlsCAFile 参数,则会出现类似于以下内容的错误:

¥With MongoDB Atlas, X.509 certificates are not Root CA certificates and will not work with the tlsCAFile parameter as self-signed certificates would. If the tlsCAFile parameter is used an error similar to the following would be raised:

MongoServerSelectionError: unable to get local issuer certificate

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

¥To connect to a MongoDB Atlas cluster using X.509 authentication the correct option to set is tlsCertificateKeyFile. The connection string already specifies the authSource and authMechanism, however they're included below as connect() options for completeness:

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 转义。

¥Note The connection string options must be URL escaped correctly.