Python 2.7 Python请求不处理仅来自一台计算机的丢失的中间证书
我正在使用一个运行CentOS(Linux)的盒子,在尝试访问特定子域进行工作时遇到以下错误:Python 2.7 Python请求不处理仅来自一台计算机的丢失的中间证书,python-2.7,ssl-certificate,python-requests,Python 2.7,Ssl Certificate,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, **k
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
根据,子域“没有发送所需的中间证书”(这是DigiCert发现的唯一问题)。然而,当我在Mac笔记本电脑上运行它时,我的代码可以毫无问题地处理这个问题,Chrome和Safari也是如此。我在笔记本电脑和linux机器上都运行Python 2.7.5。我在linux机器上运行请求1.2.0,在笔记本电脑上运行请求2.2.1,但我将两者升级到了2.4.3,它们仍然没有相同的行为
也可能相关-同一证书正在用于发送中间证书的其他子域,我的笔记本电脑和linux box都没有任何问题,因此我的笔记本电脑不应该有linux box没有的根CA
有人知道为什么它不能在我的linux机器上工作,以及我如何修复它吗?我仍然不明白为什么它在一个地方工作,而不是在另一个地方,但我确实找到了一种可以接受的解决方法,它比关闭证书验证要好得多 根据,如果安装在系统上,则将使用。所以我安装了certifi
sudo pip install certifi
然后修改了它使用的.pem文件。您可以使用certifi.where()
找到文件位置:
我将中间密钥添加到该.pem文件中,现在可以使用了。仅供参考,.pem文件希望证书显示为
-----BEGIN CERTIFICATE-----
<certificate here>
-----END CERTIFICATE-----
----开始证书-----
-----结束证书-----
警告:这不是真正的解决方案,只是一种变通方法。从安全角度来看,告诉系统信任证书可能是危险的。如果您不了解证书,则不要使用此解决方法,除非您的另一个选项是完全关闭证书验证
此外,从请求文档中:
为了安全起见,我们建议经常升级certifi
我假设当您升级certifi时,您必须重做对文件所做的任何更改。我还没有充分研究它,以了解如何进行更改,使其在certifi更新时不会被覆盖。我花了一天的时间完全理解并解决了这个问题,因此我想与大家分享我的发现会很好:-)!以下是我的结果: SSL服务器配置中的一个常见缺陷是提供不完整的证书链,通常会忽略中间证书。例如,我正在使用的一个站点在服务器的响应中没有包含常见的DigiCert“中间”证书“DigiCert TLS RSA SHA256 2020 CA1” 由于此配置缺陷很常见,大多数(但不是所有)现代浏览器都会实施一种称为“AIA抓取”的技术来动态修复此缺陷(参见示例) Python的SSL支持不支持AIA抓取,依赖于来自服务器的完整证书链;否则它会抛出一个异常,就像这样
SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1124)')))
目前正在讨论是否应将AIA获取添加到Python中,例如,在以下线程中:
我的印象是,在可预见的未来,这仍然是一个悬而未决的问题。
现在,我们如何解决这个问题?
pip安装认证fi
或
pip安装认证——升级
许多(但不是所有)Python模块都可以使用certifi
中的证书,而certifi
从Mozilla CA证书计划中获取这些证书。基本上,certifi从Mozilla站点创建一个干净的*.pem文件,并提供一个轻量级Python接口来访问该文件
import certifi
print(certifi.where())
conda activate
)您要使用证书。文件路径会有所不同。如果将此应用于基本环境,任何潜在的有缺陷证书都将使所有代码的整个SSL机制处于危险之中
示例:
/Users/username/anaconda3/envs/environment\u name/lib/python3.8/site-packages/certifi/cacert.pem
使用一个简单的文本编辑器,打开该文件,并在头的后面插入缺少的证书,如下所示
##
## Bundle of CA Root Certificates
##
...
-----BEGIN CERTIFICATE-----
+I2tIJLYrVJmuzHZ9bjPvXj1hJeRPG/cUJ9WIQDgLGB
Afr5yjK7tI4nhyfFK3TUqNaX3sNk+crOU6J
---> This is the additional certificate.
+I2tIJLYrVJmuzHZ9bjPvXj1hJeRPG/cUJ9WIQDgLGB
Afr5yjK7tI4nhyfFK3TUqNaX3sNk+crOU6J
-----END CERTIFICATE-----
##
##CA根证书束
##
...
-----开始证书-----
+I2tIJLYrVJmuzHZ9bjPvXj1hJeRPG/cUJ9WIQDgLGB
Afr5yjK7tI4nhyfFK3TUqNaX3sNk+CRU6J
--->这是附加证书。
+I2tIJLYrVJmuzHZ9bjPvXj1hJeRPG/cUJ9WIQDgLGB
Afr5yjK7tI4nhyfFK3TUqNaX3sNk+CRU6J
-----结束证书-----
包括开始和结束标记非常重要。
保存该文件,您应该已完成所有设置
您可以通过以下几行测试它是否有效:
# Python 3
import urllib.request import certifi import requests
URL = 'https://www.the_url_that_caused_the_trouble.org'
print('Trying urllib.request.urlopen().')
r = urllib.request.urlopen(URL)
print(f'urllib.request.urlopen\n================\n {r.read()[:80]}')
print('Trying requests.get().')
r = requests.get(URL)
print(f'requests.get()\n================\n {r.text[:80]}')
#Python 3
导入urllib.request导入certifi导入请求
URL='1〕https://www.the_url_that_caused_the_trouble.org'
打印('Trying urllib.request.urlopen()
r=urllib.request.urlopen(URL)
打印(f'urllib.request.urlopen\n=========================\n{r.read()[:80]}')
打印('Trying requests.get()'。)
r=请求。获取(URL)
打印(f'requests.get()\n====================\n{r.text[:80]}')
注意:通用SSL证书(例如openssl)可能位于其他位置,因此您可能需要在那里尝试相同的方法:
/Users/username/anaconda3/envs/environment\u name/ssl
瞧强>
注意事项: