Python请求仅从一台机器处理丢失的中间证书 [英] Python Requests not handling missing intermediate certificate only from one machine

查看:61
本文介绍了Python请求仅从一台机器处理丢失的中间证书的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发一个运行 CentOS (Linux) 的机器,当我尝试访问特定子域进行工作时遇到以下错误:

回溯(最近一次调用最后一次):... # 我的代码,相关调用是 requests.get(url)文件/usr/local/lib/python2.7/site-packages/requests/api.py",第60行,在get返回请求('get', url, **kwargs)文件/usr/local/lib/python2.7/site-packages/requests/api.py",第49行,请求返回 session.request(method=method, url=url, **kwargs)文件/usr/local/lib/python2.7/site-packages/requests/sessions.py",第457行,请求resp = self.send(prep, **send_kwargs)文件/usr/local/lib/python2.7/site-packages/requests/sessions.py",第569行,发送r = adapter.send(request, **kwargs)文件/usr/local/lib/python2.7/site-packages/requests/adapters.py",第420行,发送引发 SSLError(e, request=request)requests.exceptions.SSLError: [Errno 1] _ssl.c:504: error:14090086:SSL 例程:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

根据https://www.digicert.com/help/,子域是没有发送所需的中间证书"(这是 DigiCert 发现的唯一问题).但是,当我从 Mac 笔记本电脑运行它时,我的代码可以毫无问题地处理这个问题,Chrome 和 Safari 也是如此.我在我的笔记本电脑和 linux 机器上运行 Python 2.7.5.我在 linux 机器上运行 requests 1.2.0,在我的笔记本电脑上运行 2.2.1,但我将两者都升级到 2.4.3,但它们仍然没有相同的行为.

也可能相关 - 相同的证书正与其他一些发送中间证书的子域一起使用,我的笔记本电脑和 linux 机器都没有这些问题,所以我的笔记本电脑不应该有linux box没有的root CA.

有谁知道为什么它在我的 linux 机器上不起作用以及我该如何修复它?

解决方案

我仍然不明白为什么它可以在一个地方工作而不是另一个地方,但我确实找到了一种可接受的解决方法,这比关闭证书验证要好得多.

根据请求库文档,如果安装在系统上,它将使用 certifi.所以我安装了certifi

sudo pip install certifi

然后修改它使用的 .pem 文件.您可以使用 certifi.where() 找到文件位置:

<预><代码>>>>进口证明>>>certifi.where()'/usr/local/lib/python2.7/site-packages/certifi/cacert.pem'

我将中间密钥添加到该 .pem 文件中,现在可以使用了.仅供参考,.pem 文件希望证书显示为

-----BEGIN CERTIFICATE--<证书在这里>-----结束证书-----

警告:这不是真正的解决方案,只是一种解决方法.从安全的角度来看,告诉您的系统信任证书可能是危险的.如果您不了解证书,则不要使用此解决方法,除非您的其他选择是完全关闭证书验证.

此外,来自请求文档:

<块引用>

为了安全起见,我们建议经常升级证书!

我假设当您升级 certifi 时,您必须重做对文件所做的任何更改.我对它的研究还不够多,不知道如何进行更改,以便在证书更新时不会被覆盖.

I'm working on a box that's running CentOS (Linux), and I'm running into the following error when try to access a particular subdomain for work:

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

According to https://www.digicert.com/help/, the subdomain "is not sending the required intermediate certificate" (and that's the only problem DigiCert found). However, my code handles this without problem when I run it from my Mac laptop, and so do both Chrome and Safari. I'm running Python 2.7.5 on both my laptop and the linux box. I was running requests 1.2.0 on the linux box and 2.2.1 on my laptop, but I upgraded both to 2.4.3 and they still don't have the same behavior.

Also possibly relevant - the same certificate is being used with some other subdomains where the intermediate certificate is being sent, and neither my laptop nor the linux box has any problems with those, so it shouldn't be that my laptop has a root CA that the linux box doesn't have.

Does anyone know why it isn't working from my linux box and how I can fix it?

解决方案

I still don't understand why it's working one place but not another, but I did find a somewhat acceptable workaround that's much better than turning off certificate verification.

According to the requests library documentation, it will use certifi if it is installed on the system. So I installed certifi

sudo pip install certifi

and then modified the .pem file it uses. You can find the file location using certifi.where():

>>> import certifi
>>> certifi.where()
'/usr/local/lib/python2.7/site-packages/certifi/cacert.pem'

I added the intermediate key to that .pem file, and it works now. FYI, the .pem file expects certificates to show up like

-----BEGIN CERTIFICATE-----
<certificate here>
-----END CERTIFICATE-----

WARNING: This is not really a solution, only a workaround. Telling your system to trust a certificate can be dangerous from a security point of view. If you don't understand certificates then don't use this workaround unless your other option is to turn off certificate verification entirely.

Also, from the requests documentation:

For the sake of security we recommend upgrading certifi frequently!

I assume that when you upgrade certifi you'll have to redo any changes you made to the file. I haven't looked at it enough to see how to make a change that won't be overwritten when certifi gets updated.

这篇关于Python请求仅从一台机器处理丢失的中间证书的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆