我坚持持续的SSL验证问题。
我在构建一个让用户使用Mozilla Persona进行身份验证的Django应用时发现了这个错误。
(python3.4)> import requests
(python3.4)> requests.get('https://verifier.login.persona.org')
我从SSL: CERTIFICATE_VERIFY_FAILED
到requests
再到urllib3
进行ssl
追踪:
...
"/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)
这里开始变得有趣:使用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
有趣的是,问题不仅限于python3.4 [2]。
(bash)$ openssl s_client -connect github.com:443
...
Verify return code: 20 (unable to get local issuer certificate)
编辑 Steffen的评论告诉我,这种“调试”方法实际上并不提供信息,因为s_client
需要-CA路径才能验证。但是,我可以指定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
对于特定于操作系统的解决方案,我尝试清除登录KeyChain [4],但无济于事。
最后一点证据可能相关或不相关。 python3.4带有完整的pip。但是,pip3命令对我来说没用。无论我尝试安装什么:
(bash)$ pip3 install [new-lib] # pip 1.5.6
我明白了:
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]并且成功的解决方法是在我的easy_install
中使用virtualenv
安装旧版本的pip [5] ]。我正在指责这两个问题是相关的。
回顾:
verify = False
来电中不使用requests
)。openssl s_client -connect
重新创建SSL错误,但我可以通过为请求库使用的cert.pem指定-CAFile
来避免它。感谢您的帮助!
[1]:我的机器上的python2.7是使用Enthought安装的。但是安装系统版本的python2.7和请求库也可以。
[2]:使用python 2.7
查看类似问题的openssl, python requests error: "certificate verify failed"[3]:小牛似乎引入了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
答案 0 :(得分:2)
根据您提供的其他信息,您似乎已安装仅限32位版本的Python 3.4.1 from python.org。此版本主要用于OS X 10.5系统;因此,它与Apple提供的OpenSSL版本10.5相关联。您可以使用python.org中的64位/ 32位3.4.1安装程序来避免此问题;此版本推荐用于OS X 10.6+,并与较新版本的Apple的OpenSSL链接。否则,您可以使用curl
或浏览器从PyPI手动下载发行版,并安装pip
从下载的文件中安装它们。
答案 1 :(得分:1)
猜测一下:Mac OS X附带的OpenSSL(仍然是0.9.8)中有特殊的钩子,因此如果验证对OpenSSL本身提供的CA失败,则会回退到OS X密钥环。但是,如果您使用自己的OpenSSL,它就没有这种后备。
这意味着,如果您使用内置的OpenSSL和python2,它将成功验证站点是否在OS X密钥环内找到CA,即使它不在请求本身提供的证书存储中。但是如果您已经针对自己的OpenSSL编译了python3,它将只使用请求本身提供的CA而不会回退到OS X密钥环,因此无法验证CA是否不在请求密钥环中。
有关Mac OS X此“功能”的详细信息及其引入的问题,请参阅https://hynek.me/articles/apple-openssl-verification-surprises/。
不幸的是,这并没有解释为什么openssl成功验证了请求库的默认证书,除非涉及另一个OpenSSL版本,即python3使用的版本没有密钥环回退和命令行上的最新版本后备。