TLS/SSL和PyMongo#

PyMongo supports connecting to MongoDB over TLS/SSL. This guide covers the configuration options supported by PyMongo. See the server documentation to configure MongoDB.

警告

行业最佳实践建议使用TLS 1.1或更高版本,有些法规要求使用TLS 1.1或更高版本。虽然PyMongo不需要对应用程序进行任何更改就可以使用最新的协议,但是某些操作系统或版本可能无法提供足够新的OpenSSL版本来支持它们。

超过10.13(High Sierra)的macOS用户需要从 python.orghomebrewmacports 或其他类似来源。

Linux或其他非macOS Unix的用户可以检查他们的OpenSSL版本,如下所示:

$ openssl version

如果版本号小于1.0.1,则TLS 1.1或更高版本的支持不可用。请与您的操作系统供应商联系以获得解决方案或升级到更新的发行版。

您可以通过安装 requests 模块并执行以下命令:

python -c "import requests; print(requests.get('https://www.howsmyssl.com/a/check', verify=False).json()['tls_version'])"

您应该看到“TLS 1.X”,其中X大于等于1。

您可以在此处阅读有关TLS版本及其安全含义的更多信息:

https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html#only-support-strong-protocols

基本配置#

在许多情况下,通过TLS/SSL连接到MongoDB只需要传递 tls=True 作为关键字参数 MongoClient **

>>> client = pymongo.MongoClient('example.com', tls=True)

或通过 tls=true 在URI::

>>> client = pymongo.MongoClient('mongodb://example.com/?tls=true')

这会将PyMongo配置为使用TLS连接到服务器,验证服务器的证书,并验证您尝试连接的主机是否列在该证书中。

证书验证策略#

默认情况下,在启用TLS时,PyMongo被配置为需要来自服务器的证书。这是可以使用 tlsAllowInvalidCertificates 选择。要禁用此要求,请通过 tlsAllowInvalidCertificates=True 作为关键字参数::

>>> client = pymongo.MongoClient('example.com',
...                              tls=True,
...                              tlsAllowInvalidCertificates=True)

或者,在URI中:

>>> uri = 'mongodb://example.com/?tls=true&tlsAllowInvalidCertificates=true'
>>> client = pymongo.MongoClient(uri)

指定CA文件#

在某些情况下,您可能希望将PyMongo配置为使用一组特定的CA证书。当您充当自己的证书颁发机构而不是使用由知名颁发机构签署的服务器证书时,最常出现这种情况。这个 tlsCAFile 选项采用CA文件的路径。它可以作为关键字参数传递::

>>> client = pymongo.MongoClient('example.com',
...                              tls=True,
...                              tlsCAFile='/path/to/ca.pem')

或者,在URI中:

>>> uri = 'mongodb://example.com/?tls=true&tlsCAFile=/path/to/ca.pem'
>>> client = pymongo.MongoClient(uri)

指定证书吊销列表#

这个 tlsCRLFile 选项采用CRL文件的路径。它可以作为关键字参数传递::

>>> client = pymongo.MongoClient('example.com',
...                              tls=True,
...                              tlsCRLFile='/path/to/crl.pem')

或者,在URI中:

>>> uri = 'mongodb://example.com/?tls=true&tlsCRLFile=/path/to/crl.pem'
>>> client = pymongo.MongoClient(uri)

备注

证书吊销列表和 OCSP 不能一起使用。

客户端证书#

可以将PyMongo配置为使用 tlsCertificateKeyFile 选项::

>>> client = pymongo.MongoClient('example.com',
...                              tls=True,
...                              tlsCertificateKeyFile='/path/to/client.pem')

如果客户端证书的私钥存储在单独的文件中,则应将其与证书文件串联。例如,要串联PEM格式的证书文件 cert.pem 和PEM格式的密钥文件 key.pem 放入单个文件中 combined.pem ,在Unix系统上,用户可以运行::

$ cat key.pem cert.pem > combined.pem

可以使用连接的证书密钥文件配置PyMongo tlsCertificateKeyFile 选项::

>>> client = pymongo.MongoClient('example.com',
...                              tls=True,
...                              tlsCertificateKeyFile='/path/to/combined.pem')

如果证书密钥文件中包含的私钥已加密,则用户可以提供密码或口令短语,以使用 tlsCertificateKeyFilePassword 选项::

>>> client = pymongo.MongoClient('example.com',
...                              tls=True,
...                              tlsCertificateKeyFile='/path/to/combined.pem',
...                              tlsCertificateKeyFilePassword=<passphrase>)

这些选项也可以作为MongoDB URI的一部分传递。

OCSP#

从PyMongo 3.11开始,如果PyMongo安装了“ocsp”附加文件:

python -m pip install pymongo[ocsp]

通过以下方式启用证书吊销检查 OCSP (Online Certification Status Protocol) . MongoDB 4.4版+ staples OCSP responses PyMongo将验证的TLS握手,如果装订的OCSP响应无效或指示对等证书已吊销,则TLS握手失败。

当连接到4.4以上版本的服务器时,或者当4.4+版本的MongoDB没有固定OCSP响应时,如果对等证书指定了OCSP端点,PyMongo将尝试直接连接到OCSP端点。只有在这种情况下,如果响应指示证书被吊销,TLS握手才会失败。无效或格式错误的响应将被忽略,这将使可用性优于最大安全性。

TLS错误故障排除#

TLS错误通常分为三类-证书验证失败、协议版本不匹配或证书吊销检查失败。类似于以下内容的错误消息表示OpenSSL无法验证服务器的证书:

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed

这种情况经常发生,因为OpenSSL无权访问系统的根证书或证书已过期。Linux用户应确保安装了来自其Linux供应商的最新根证书更新。使用从python.org下载的Python3.7或更新版本的MacOS用户 may have to run a script included with python 要安装根证书::

open "/Applications/Python <YOUR PYTHON VERSION>/Install Certificates.command"

旧的PyPy便携版本的用户可能必须 set an environment variable 告诉OpenSSL在哪里可以找到根证书。使用 certifi module 来自pypi::

$ pypy -m pip install certifi
$ export SSL_CERT_FILE=$(pypy -c "import certifi; print(certifi.where())")

与以下消息类似的错误消息表示Python使用的OpenSSL版本不支持足够新的TLS协议来连接到服务器:

[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version

行业最佳实践建议在某些MongoDB部署中禁用较旧的TLS协议,有些法规要求这样做。某些部署可能禁用TLS 1.0,其他部署可能禁用TLS 1.0和TLS 1.1。有关故障排除步骤和解决方案,请参阅本文档前面的警告。

与以下消息类似的错误消息表示证书吊销检查失败:

[('SSL routines', 'tls_process_initial_server_flight', 'invalid status response')]

OCSP 了解更多详细信息。

在MongoDB<=4.0上,Python3.10+与TLS/SSL不兼容#

请注意 changes made to the ssl module in Python 3.10+ 可能会导致与MongoDB<=4.0不兼容。以下是此组合可能出现的一些错误示例:

SSL handshake failed: localhost:27017: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:997)
SSL handshake failed: localhost:27017: EOF occurred in violation of protocol (_ssl.c:997)

MongoDB服务器日志可能会显示以下错误:

2021-06-30T21:22:44.917+0100 E NETWORK  [conn16] SSL: error:1408A0C1:SSL routines:ssl3_get_client_hello:no shared cipher

要解决此问题,请使用Python<=3.10,升级到MongoDB 4.2+,或使用 OCSP Extra,它依赖于PyOpenSSL。