Python3 上 Pymongo 的 SSL 握手问题

abh*_*ngh 11 python ssl azure python-3.x azure-cosmosdb-mongoapi

尝试连接到 Azure CosmosDB mongo 服务器会导致 SSL 握手错误。

我正在使用Python3Pymongo连接到我的 Azure CosmosDB。如果我使用 Python27 运行代码,则连接工作正常,但在使用 Python3 时会导致以下错误:

import pymongo
from pymongo import MongoClient
import json
import sys

def check_server_status(client, data):
   '''check the server status of the connected endpoint'''
   db = client.result_DB
   server_status = db.command('serverStatus')
   print('Database server status:')
   print(json.dumps(server_status, sort_keys=False, indent=2, separators=(',', ': ')))
   coll = db.file_result
   print (coll)
   coll.insert_one(data)

def main():
    uri = "mongodb://KEY123@backend.documents.azure.com:10255/?ssl=true&replicaSet=globaldb"
    client = pymongo.MongoClient(uri)
    emp_rec1 = {
        "name":"Mr.Geek",
        "eid":24,
        "location":"delhi"
        }
    check_server_status(client, emp_rec1)

if __name__ == "__main__":
    main()
Run Code Online (Sandbox Code Playgroud)

运行此Python3结果到以下错误:

pymongo.errors.ServerSelectionTimeoutError: SSL 握手失败: backendstore.documents.azure.com:10255: [SSL: CERTIFICATE_VERIFY_FAILED] 证书验证失败 (_ssl.c:749)

这是我运行相同代码时的成功输出Python27

数据库服务器状态:{ "_t": "OKMongoResponse", "ok": 1 } Collection(Database(MongoClient(host=['backend.documents.azure.com:10255'], document_class=dict, tz_aware=False, connect =True, ssl=True, replicaset='globaldb'), u'result_DB'), u'file_result')

Ank*_*mar 34

在 Windows 上你可以这样做

pip安装证书

然后在代码中使用它:

import certifi
ca = certifi.where()

client = pymongo.MongoClient(
"mongodb+srv://username:password@cluster0.xxxxx.mongodb.net/xyzdb?retryWrites=true&w=majority", tlsCAFile=ca)
Run Code Online (Sandbox Code Playgroud)

  • MongoClient 需要 TLS 证书来进行安全通信,有时 python 无法通过 TLS 请求,因此这里我们明确提到 MongoClient 使用 certifi 包向 mongodb 请求 (4认同)
  • 这到底是做什么的?我尝试过,它确实解决了我的问题,但我很难理解问题是什么(因为它发生在一夜之间)以及这个技巧如何解决它。 (2认同)

abh*_*ngh 10

解决了此更改的问题:

client = pymongo.MongoClient(uri, ssl_cert_reqs=ssl.CERT_NONE)
Run Code Online (Sandbox Code Playgroud)

  • 这是否仅仅意味着它不使用 TLS 握手?对于生产中的东西来说,这似乎不是最好的主意。 (4认同)
  • 这对于测试来说很好,也许在开发场景中,当您知道要连接的内容时。但这不是我所说的解决方案。 (2认同)

Pet*_*Pan 7

本节Troubleshooting TLS Errors的PyMongo官方文档`TLS / SSL和PyMongo的引入问题如下。

TLS 错误通常分为两类,证书验证失败或协议版本不匹配。类似于以下的错误消息表示 OpenSSL 无法验证服务器的证书:

[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed

这通常是因为 OpenSSL 无权访问系统的根证书或证书已过期。Linux 用户应确保他们安装了 Linux 供应商提供的最新根证书更新。使用从 python.org 下载的 Python 3.6.0 或更高版本的 macOS 用户可能必须运行 python 附带的脚本来安装根证书:

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

旧 PyPy 和 PyPy3 便携式版本的用户可能必须设置一个环境变量来告诉 OpenSSL 在哪里可以找到根证书。使用pypi 中的certifi 模块可以轻松完成此操作:

$ pypy -m pip install certifi
$ export SSL_CERT_FILE=$(pypy -c "import certifi; print(certifi.where())")
Run Code Online (Sandbox Code Playgroud)

您可以尝试按照上面的描述来解决您的问题,这似乎是针对 Linux 和 Mac 用户的。在 Windows 上,我无法在 Python3.73.6. 如果您有任何疑问,请随时告诉我。


小智 6

尝试从 Digital Ocean 连接 mongodb 时遇到同样的问题,通过在 MongoClient 中使用此函数和 params 解决:

def get_client(host,port,username,password,db):
      return MongoClient('mongodb://{}:{}/'.format(host,port),
                         username=username,
                         password=password,
                         authSource=db,
                         ssl=True,ssl_cert_reqs=ssl.CERT_NONE)

client = get_client("host-ip","port","username","password","db-name")
Run Code Online (Sandbox Code Playgroud)