当 ssl 设置看起来正常时,为啥我在 Python 中得到 [SSL: CERTIFICATE_VERIFY_FAILED]?
Posted
技术标签:
【中文标题】当 ssl 设置看起来正常时,为啥我在 Python 中得到 [SSL: CERTIFICATE_VERIFY_FAILED]?【英文标题】:Why do I get [SSL: CERTIFICATE_VERIFY_FAILED] in Python when ssl setup looks OK?当 ssl 设置看起来正常时,为什么我在 Python 中得到 [SSL: CERTIFICATE_VERIFY_FAILED]? 【发布时间】:2019-05-06 18:06:07 【问题描述】:我正在开发一个 Python 应用程序,以通过安全的 websocket 协议与在 localhost 上运行的服务进行通信。 这是一个示例代码:
import json
import asyncio
import websockets
import ssl
import certifi
ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(certifi.where())
ssl_context.load_default_certs()
query =
"jsonrpc": "2.0",
"method": "queryHeadsets",
"params": ,
"id": 1
json = json.dumps(query)
async def query(json):
async with websockets.connect("wss://emotivcortex.com:54321") as ws:
await ws.send(json)
response = await ws.recv()
print(response)
asyncio.get_event_loop().run_until_complete(query(json))
问题是 ssl 握手一直失败并出现以下错误:
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)
我正在运行 Windows 10,Python 3.7.3 64 位
$pip list
Package Version
---------- --------
certifi 2019.3.9
pip 19.0.3
setuptools 40.8.0
websockets 7.0
我已经检查了服务提供的证书。它似乎有效并由 COMODO 签名。 我试过了:
ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(certifi.where())
print(ssl.get_default_verify_paths())
print(ssl_context.cert_store_stats())
ssl_context.load_default_certs()
print(ssl_context.get_ca_certs())
发现有几个 COMODO CA 证书可用于 python。但我仍然得到错误。
如果有帮助,这里是完整的错误消息:
SSL handshake failed on verifying the certificate
protocol: <asyncio.sslproto.SSLProtocol object at 0x0000020C11283048>
transport: <_SelectorSocketTransport fd=508 read=polling write=<idle, bufsize=0>>
Traceback (most recent call last):
File "C:\Users\Matyas2\Python\lib\asyncio\sslproto.py", line 625, in _on_handshake_complete
raise handshake_exc
File "C:\Users\Matyas2\Python\lib\asyncio\sslproto.py", line 189, in feed_ssldata
self._sslobj.do_handshake()
File "C:\Users\Matyas2\Python\lib\ssl.py", line 763, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)
SSL error in data received
protocol: <asyncio.sslproto.SSLProtocol object at 0x0000020C11283048>
transport: <_SelectorSocketTransport closing fd=508 read=idle write=<idle, bufsize=0>>
Traceback (most recent call last):
File "C:\Users\Matyas2\Python\lib\asyncio\sslproto.py", line 526, in data_received
ssldata, appdata = self._sslpipe.feed_ssldata(data)
File "C:\Users\Matyas2\Python\lib\asyncio\sslproto.py", line 189, in feed_ssldata
self._sslobj.do_handshake()
File "C:\Users\Matyas2\Python\lib\ssl.py", line 763, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)
Traceback (most recent call last):
File "test.py", line 37, in <module>
asyncio.get_event_loop().run_until_complete(query(json))
File "C:\Users\Matyas2\Python\lib\asyncio\base_events.py", line 584, in run_until_complete
return future.result()
File "test.py", line 32, in query
async with websockets.connect("wss://emotivcortex.com:54321") as ws:
File "C:\Users\Matyas2\Python\lib\site-packages\websockets\py35\client.py", line 2, in __aenter__
return await self
File "C:\Users\Matyas2\Python\lib\site-packages\websockets\py35\client.py", line 12, in __await_impl__
transport, protocol = await self._creating_connection
File "C:\Users\Matyas2\Python\lib\asyncio\base_events.py", line 986, in create_connection
ssl_handshake_timeout=ssl_handshake_timeout)
File "C:\Users\Matyas2\Python\lib\asyncio\base_events.py", line 1014, in _create_connection_transport
await waiter
File "C:\Users\Matyas2\Python\lib\asyncio\sslproto.py", line 526, in data_received
ssldata, appdata = self._sslpipe.feed_ssldata(data)
File "C:\Users\Matyas2\Python\lib\asyncio\sslproto.py", line 189, in feed_ssldata
self._sslobj.do_handshake()
File "C:\Users\Matyas2\Python\lib\ssl.py", line 763, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)
与 Internet 中的服务器的 SSL 连接工作正常。 我错过了什么? 我做错了什么?
如果需要,我很乐意提供其他信息。
编辑: 该证书适用于 emotivcortex.com,由 COMODO RSA 域验证安全服务器 CA 颁发,因此我认为它不是自签名证书。 OpenSSL:
$python -c "import ssl; print(ssl.OPENSSL_VERSION)"
OpenSSL 1.1.0j 20 Nov 2018
【问题讨论】:
您使用的是自签名证书吗? 我遇到了类似的错误:SSLV3_ALERT_HANDSHAKE_FAILURE。我使用的是 Mac,这是在 virtualenv 中的 Python 2 上。我必须从我的机器上卸载现有的 python,然后使用 brew:brew install python@2 --with-brewed-openssl
再次安装它。然后我用这个python创建了一个新环境,一切都修复了。
同时检查你是否安装了最新的 Open SSL 版本。打开 python 控制台并运行此脚本以检查已安装的 OpenSSL 版本:import ssl
ssl.OPENSSL_VERSION
我认为作为诊断的第一步,您应该验证您安装了正确的 CA 证书。使用例如openssl
命令行来验证证书,使用与您在 Python 代码中使用的相同的权限。如果您无法首先确认证书是否正确验证,则无法判断问题是否出在您的 Python 代码中。
一个典型的错误是服务器没有提供验证证书所需的所有链证书。桌面浏览器通常会尝试通过从缓存中填充丢失的证书或从 Internet 下载这些证书来解决此问题,但 Python、Java ......不要。
【参考方案1】:
问题是由于缺少中间 CA 证书造成的。
通过检查 OpenSSL 中服务提供的证书,我发现该证书是由“COMODO RSA Domain Validation Secure Server CA”颁发的。这个特定机构的 CA 证书实际上不存在于 python 包 certifi
的 CA 包中(有不同的 COMODO...证书)。
解决方案
从 CA 的网页手动下载 PEM 格式的缺失证书,并将其添加到代码中使用的 CA 包中。
另外,应用代码中存在错误:
调用函数websockets.connect()
时,传递一个关键字参数ssl=ssl_context
,以便实际使用前面指定的CA 包。
正确的代码如下所示:
import json
import asyncio
import websockets
import ssl
import certifi
ssl_context = ssl.create_default_context()
ssl_context.load_verify_locations(certifi.where())
query =
"jsonrpc": "2.0",
"method": "queryHeadsets",
"params": ,
"id": 1
json = json.dumps(query)
async def query(json):
async with websockets.connect("wss://emotivcortex.com:54321", ssl=ssl_context) as ws:
await ws.send(json)
response = await ws.recv()
print(response)
asyncio.get_event_loop().run_until_complete(query(json))
非常感谢 larsks 和 Steffen Ullrich 为我指明了正确的方向。
【讨论】:
以上是关于当 ssl 设置看起来正常时,为啥我在 Python 中得到 [SSL: CERTIFICATE_VERIFY_FAILED]?的主要内容,如果未能解决你的问题,请参考以下文章
当我在 ngOnInit() 中使用 router.getCurrentNavigation() 时,它会给我类型错误,但是当我在构造函数中使用它时,它工作正常,为啥?
为啥当我将我的国际象棋项目作为可运行的 jar 文件运行时,我得到一个奇怪的行为,而当我在 eclipse 中运行它时,一切正常?