Rob*_*tts 7 ssl-certificate python-2.7 python-requests
我正在开发一个运行 CentOS (Linux) 的机器,当尝试访问特定子域进行工作时遇到以下错误:
Traceback (most recent call last):
... # My code, relevant call is requests.get(url)
File "/usr/local/lib/python2.7/site-packages/requests/api.py", line 60, in get
return request('get', url, **kwargs)
File "/usr/local/lib/python2.7/site-packages/requests/api.py", line 49, in request
return session.request(method=method, url=url, **kwargs)
File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 457, in request
resp = self.send(prep, **send_kwargs)
File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 569, in send
r = adapter.send(request, **kwargs)
File "/usr/local/lib/python2.7/site-packages/requests/adapters.py", line 420, in send
raise SSLError(e, request=request)
requests.exceptions.SSLError: [Errno 1] _ssl.c:504: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
Run Code Online (Sandbox Code Playgroud)
根据https://www.digicert.com/help/,子域“没有发送所需的中间证书”(这是 DigiCert 发现的唯一问题)。然而,当我从 Mac 笔记本电脑上运行我的代码时,它可以毫无问题地处理这个问题,Chrome 和 Safari 也是如此。我在我的笔记本电脑和 Linux 机器上运行 Python 2.7.5。我在 Linux 机器上运行 requests 1.2.0,在笔记本电脑上运行 requests 2.2.1,但我将两者都升级到 2.4.3,但它们仍然没有相同的行为。
也可能相关 - 相同的证书正在与发送中间证书的其他一些子域一起使用,并且我的笔记本电脑和 Linux 盒子都没有任何问题,所以我的笔记本电脑不应该有一个根 CA linux盒子没有。
有谁知道为什么它在我的 linux 盒子上不起作用以及如何修复它?
Mar*_*epp 14
我花了一天的时间来完全理解并解决这个问题,所以我认为与大家分享我的发现会很高兴:-)!这是我的结果:
SSL 服务器配置中的一个常见缺陷是提供不完整的证书链,通常会忽略中间证书。例如,我正在使用的网站在服务器响应中不包含常见的 DigiCert“中间”证书“DigiCert TLS RSA SHA256 2020 CA1”。
由于此配置缺陷很常见,因此大多数(但并非所有)现代浏览器都实现了一种称为“AIA Fetching”的技术来即时修复此问题(请参阅https://www.thesslstore.com/blog/aia-fetching/)。
Python 的 SSL 支持不支持 AIA Fetching,依赖于服务器的完整证书链;否则它会抛出异常,就像这样
SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1124)')))
Run Code Online (Sandbox Code Playgroud)
关于是否应将 AIA Fetching 添加到 Python 中的讨论正在进行中,例如在此线程中:https ://bugs.python.org/issue18617#msg293894 。
我的印象是,在可预见的未来,这仍然是一个悬而未决的问题。
现在,我们该如何解决这个问题?
certifi
如果您还没有安装,请安装,或者更新它pip install certifi
或者
pip install certifi --upgrade
许多(但不是全部)Python 模块可以使用来自certifi
Mozilla CA 证书计划( https://wiki.mozilla.org/CA )的证书。基本上,certifi 从 Mozilla 站点创建一个干净的 *.pem 文件,并提供用于访问该文件的轻量级 Python 接口。certifi
将丢失的证书下载为 PEM 语法的文件,例如从https://www.digicert.com/kb/digicert-root-certificates.htm或从受信任的浏览器下载。
找到 certifi *.PEM 证书文件
import certifi
print(certifi.where())
Run Code Online (Sandbox Code Playgroud)
注意:我建议首先激活您想要使用证书的虚拟环境(例如conda activate <envname>
) 。文件路径会有所不同。如果您将此应用到您的基础环境,任何潜在的有缺陷的证书都会使您所有代码的整个 SSL 机制面临风险。
示例: /Users/用户名/anaconda3/envs/环境名称/lib/python3.8/site-packages/certifi/cacert.pem
使用一个简单的文本编辑器,打开该文件,然后在标题后面的开头插入缺少的证书,如下所示
## ## CA 根证书捆绑包 ## ... -----开始证书----- +I2tIJLYrVJmuzHZ9bjPvXj1hJeRPG/cUJ9WIQDgLGB Afr5yjK7tI4nhyfFK3TUqNaX3sNK+CROU6J ---> 这是附加证书。 +I2tIJLYrVJmuzHZ9bjPvXj1hJeRPG/cUJ9WIQDgLGB Afr5yjK7tI4nhyfFK3TUqNaX3sNK+CROU6J -----证书结束-----
包含开始和结束标记很重要。
保存文件,一切就都准备好了!
您可以使用以下几行测试它是否有效:
#Python 3 导入 urllib.request 导入证书导入请求 URL = 'https://www.the_url_that_caused_the_trouble.org' print('正在尝试 urllib.request.urlopen().') r = urllib.request.urlopen(URL) print(f'urllib.request.urlopen\n================\n {r.read()[:80]}') print('尝试 requests.get().') r = requests.get(URL) print(f'requests.get()\n================\n {r.text[:80]}')
注意:一般的 SSL 证书(例如 openssl 的证书)可能位于其他地方,因此您可能必须在那里尝试相同的方法:
/用户/用户名/anaconda3/envs/环境名称/ssl
瞧!
笔记:
certifi
或创建新的虚拟环境时,更改可能会丢失,但我认为这实际上是很好的设计,因为它不会对整个系统进行临时安全调整。certifi
滞后于 Mozilla 的发布。如果您想将最新版本的 Mozilla CA 捆绑包与 一起使用certifi
,您可以使用 https://github.com/mfhepp/update_certifi_certificates中的我的脚本。我仍然不明白为什么它在一个地方起作用而在另一个地方不起作用,但我确实找到了一种可以接受的解决方法,它比关闭证书验证要好得多。
根据requests 库文档,如果系统上安装了certifi ,它将使用certifi 。所以我安装了证书
sudo pip install certifi
Run Code Online (Sandbox Code Playgroud)
然后修改它使用的 .pem 文件。您可以使用以下命令找到文件位置certifi.where()
:
>>> import certifi
>>> certifi.where()
'/usr/local/lib/python2.7/site-packages/certifi/cacert.pem'
Run Code Online (Sandbox Code Playgroud)
我将中间密钥添加到该 .pem 文件中,现在它可以工作了。仅供参考,.pem 文件期望证书显示如下
-----BEGIN CERTIFICATE-----
<certificate here>
-----END CERTIFICATE-----
Run Code Online (Sandbox Code Playgroud)
警告:这并不是真正的解决方案,只是一种解决方法。从安全角度来看,告诉您的系统信任证书可能很危险。如果您不了解证书,则不要使用此解决方法,除非您的其他选择是完全关闭证书验证。
另外,从请求文档中:
为了安全起见,我们建议经常升级证书!
我假设当您升级 certifi 时,您必须重做对该文件所做的任何更改。我还没有仔细研究过如何进行更改,以免在 certifi 更新时被覆盖。
归档时间: |
|
查看次数: |
12329 次 |
最近记录: |