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 的 MongoDB 叢集,但未啟用 tls/ssl 選項,則 mongoose.connect() 會拋出以下錯誤

MongooseServerSelectionError:連線到 127.0.0.1:27017 在 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:無法驗證第一個憑證

此錯誤通常是由自簽署的 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:主機名稱/IP 與憑證的替代名稱不符:主機:hostname1。不是憑證的 CN:hostname2

SSL 憑證的通用名稱必須與您的連線字串中的主機名稱一致。如果 SSL 憑證適用於 hostname2.mydomain.com,則您的連線字串必須連線到 hostname2.mydomain.com,而不是可能等同於 hostname2.mydomain.com 的任何其他主機名稱或 IP 位址。對於複本集,這也表示 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:無法取得本機發行者憑證

若要使用 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 編碼。