我被一个持久的SSL验证问题困扰。
SSL: CERTIFICATE_VERIFY_FAILED
我在构建一个使用Mozilla Persona进行用户身份验证的Django应用程序时发现了这个错误。
(python3.4)> import requests
(python3.4)> requests.get('https://verifier.login.persona.org')
我从
requests
到urllib3
再到ssl
发现出现了SSL: CERTIFICATE_VERIFY_FAILED
的追溯。...
"/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/ssl.py", line 805, in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:598)
...
"/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/requests-2.4.1-py3.4.egg/requests/packages/urllib3/connectionpool.py", line 543, in urlopen
raise SSLError(e)
requests.packages.urllib3.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:598)
...
"/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/requests-2.4.1-py3.4.egg/requests/adapters.py", line 420, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:598)
Python3和Python2的区别
这里开始变得有趣了:当使用Python2.7时,我没有遇到同样的问题:
(python2.7)> import requests
(python2.7)> requests.get('https://verifier.login.persona.org')
<Response [200]>
我的第一个想法是,两个版本的requests
可能使用了不同的证书[1],所以当我发现这两个文件完全相同时,我非常惊讶:
(bash)$ diff `python3.4 -c "import requests; print(requests.certs.where())"` \
`python2.7 -c "import requests; print requests.certs.where()"`
# no diff
使用-CAFile在openssl中重现错误并解决
有趣的是,这个问题并不局限于python3.4 [2]。
(bash)$ openssl s_client -connect github.com:443
...
Verify return code: 20 (unable to get local issuer certificate)
编辑 Steffen 的评论告诉我,这种“调试”方法实际上并不提供信息,因为 s_client
需要 -CApath 才能进行验证。然而,我可以指定与 requests
包使用的相同证书,但我没有收到相同的错误仍然很有趣:
(bash)$ openssl s_client -connect github.com:443 \
-CAfile `python3 -c 'import requests; print(requests.certs.where())'`
...
Verify return code: 0 (ok)
在这一点上,我完全不懂。我不知道这是否真的是一个 openssl
问题,还是与OSX Mavericks[3]有关。这是我正在使用的openssl版本:
(bash)$ openssl version
OpenSSL 1.0.1f 6 Jan 2014
Mavericks KeyChain.app
针对操作系统的解决方案,我已经尝试清除我的登录 KeyChain[4],但仍然无法解决问题。
pip相关问题
还有一个可能与此相关的细节。python3.4 自带 pip,但 pip3 命令对我来说毫无用处。无论我尝试安装什么:
(bash)$ pip3 install [new-lib] # pip 1.5.6
I get:
Downloading/unpacking [new-lib]
Cannot fetch index base URL https://pypi.python.org/simple/
Could not find any downloads that satisfy the requirement [new-lib]
Cleaning up...
No distributions at all found for [new-lib]
Storing debug log for failure in ~/.pip/pip.log
尽管这不是一个(明显的)SSL错误,但它看起来很相似[5],成功的解决方法是在我的
virtualenv
s中使用easy_install
安装旧版本的pip[5]。 我抱着希望,认为这两个问题是相关的。总结:
- 寻求SSL证书失败错误的可能解决方案(不使用
verify = False
在requests
调用中)。 - 我在python3.4中遇到错误,但在python2.7中没有遇到,尽管在两种情况下使用的cert.pem完全相同。
- 虽然我可以使用
openssl s_client -connect
重新创建SSL错误,但是我可以通过将-CAFile
指定给requests库使用的cert.pem 来避免该错误。 - 我最好的猜测是这是特定于Mavericks的问题,但我不知道如何继续。
- 我希望找到一个解决方案,能让我像预期的那样使用pip3来安装python3.4包。
[1]:我的机器上的python2.7是使用Enthought安装的。 但是安装系统版本的python2.7和requests库也可以正常工作。
[2]:请参见openssl,python requests error: "certificate verify failed",了解在使用python 2.7时出现类似问题的情况。
[3]:看起来Mavericks引入了openssl的一个更改?http://curl.haxx.se/mail/archive-2013-10/0036.html [4]:从这里清除KeyChain.app:https://superuser.com/a/721629/261875 [5]:使用pip3出现SSL错误:https://stackoverflow.com/a/22051466/2506078
openssl version
返回自2013年2月起的“0.9.8y”(早于您发布的有关OpenSSL更改的链接)。 - Ian Stapleton Cordascopythonx.x -c 'import sys;print(sys.version)'
的结果。 - Ned Deily