关于ssl:Python请求抛出SSLError

Python Requests throwing SSLError

我正在编写一个简单的脚本,它涉及到CA、jSpring安全检查、重定向等。我想使用Kenneth Reitz的python请求,因为这是一项伟大的工作!但是,CA需要通过SSL进行验证,因此我必须先通过该步骤。我不知道python需要什么请求?这个SSL证书应该放在哪里?

1
2
3
4
5
6
7
8
9
10
Traceback (most recent call last):
  File"./test.py", line 24, in <module>
  response = requests.get(url1, headers=headers)
  File"build/bdist.linux-x86_64/egg/requests/api.py", line 52, in get
  File"build/bdist.linux-x86_64/egg/requests/api.py", line 40, in request
  File"build/bdist.linux-x86_64/egg/requests/sessions.py", line 209, in request
  File"build/bdist.linux-x86_64/egg/requests/models.py", line 624, in send
  File"build/bdist.linux-x86_64/egg/requests/models.py", line 300, in _build_response
  File"build/bdist.linux-x86_64/egg/requests/models.py", line 611, in send
requests.exceptions.SSLError: [Errno 1] _ssl.c:503: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed


您遇到的问题是由不受信任的SSL证书引起的。

就像前面评论中提到的@dirk一样,最快的解决方法是设置verify=False

1
requests.get('https://example.com', verify=False)

请注意,这将导致证书无法验证。这将使您的应用程序面临安全风险,例如中间人攻击。

当然,运用判断。正如注释中提到的,对于快速/一次性应用程序/脚本,这可能是可以接受的,但实际上不应该转到生产软件。

如果在您的特定上下文中不接受跳过证书检查,请考虑以下选项,您的最佳选择是将verify参数设置为一个字符串,该字符串是证书的.pem文件的路径(您应该通过某种安全方式获得)。

因此,从2.0版开始,verify参数接受以下值及其各自的语义:

  • True:使证书根据库自己的受信任证书颁发机构进行验证(注意:您可以通过certifi库查看请求使用的根证书,该库是从请求中提取的rcs的信任数据库:certifi-人类信任数据库)。
  • False:完全绕过证书验证。
  • 用于验证证书的请求的CA捆绑文件的路径。

来源:请求-SSL证书验证

还可以查看同一链接上的cert参数。


来自有关SSL验证的请求文档:

Requests can verify SSL certificates for HTTPS requests, just like a web browser. To check a host’s SSL certificate, you can use the verify argument:

1
>>> requests.get('https://kennethreitz.com', verify=True)

如果您不想验证您的SSL证书,请使EDOCX1[0]


您可以通过verify传递要使用的CA文件名:

1
2
cafile = 'cacert.pem' # http://curl.haxx.se/ca/cacert.pem
r = requests.get(url, verify=cafile)

如果您使用verify=True,那么requests使用自己的CA集,该CA集可能没有签署您的服务器证书的CA。


江户十一〔四〕号

  • 在python 2.7.6@ubuntu 14.04.4 LTS上测试
  • 在python 2.7.5@macosx 10.9.5上测试(Mavericks)

打开此问题(2012-05)时,请求版本为0.13.1。在版本2.4.1(2014-09)中,引入了"安全"附加程序,如果可用,则使用certifi包。

现在(2016-09)主版本是2.11.1,没有verify=False就可以很好地工作。如果安装了requests[security]附加设备,则无需使用requests.get(url, verify=False)


我在使用aws boto3时遇到了相同的问题和ssl证书验证失败的问题,通过查看boto3代码,我发现REQUESTS_CA_BUNDLE没有设置,所以我通过手动设置修复了这两个问题:

1
2
3
4
5
6
7
8
9
from boto3.session import Session
import os

# debian
os.environ['REQUESTS_CA_BUNDLE'] = os.path.join(
    '/etc/ssl/certs/',
    'ca-certificates.crt')
# centos
#   'ca-bundle.crt')

对于aws cli,我想在~/.bashrc中设置requests ou ca ou bundle可以解决这个问题(没有测试,因为我的aws cli在没有它的情况下工作)。

1
2
REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt # ca-bundle.crt
export REQUESTS_CA_BUNDLE


如果您有一个依赖于requests的库,并且您不能修改验证路径(与pyvmomi类似),那么您必须找到与请求捆绑在一起的cacert.pem并将您的CA附加到那里。以下是查找cacert.pem位置的通用方法:

窗户

1
2
3
4
C:\>python -c"import requests; print requests.certs.where()"
c:\Python27\lib\site-packages
equests-2.8.1-py2.7.egg
equests\cacert.pem

Linux

1
2
3
4
5
6
7
#  (py2.7.5,requests 2.7.0, verify not enforced)
root@host:~/# python -c"import requests; print requests.certs.where()"
/usr/lib/python2.7/dist-packages/certifi/cacert.pem

#  (py2.7.10, verify enforced)
root@host:~/# python -c"import requests; print requests.certs.where()"
/usr/local/lib/python2.7/dist-packages/requests/cacert.pem

顺便说一下@requests devs,把你自己的cacerts和request捆绑在一起真的,真的很烦人…尤其是,您似乎没有首先使用系统CA存储,而且这在任何地方都没有记录。

更新

在使用库且无法控制CA束位置的情况下,还可以显式将CA束位置设置为主机范围的CA束:

1
REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-bundle.crt python -c"import requests; requests.get('https://somesite.com';)"

我使用gspread也面临同样的问题,这些命令对我很有用:

1
2
sudo pip uninstall -y certifi
sudo pip install certifi==2015.04.28


如果要删除警告,请使用下面的代码。

1
2
3
import urllib3

urllib3.disable_warnings()

request.getpost方法得到的verify=False


我找到了解决类似问题的具体方法。其思想是指向存储在系统中并由另一个基于SSL的应用程序使用的cacert文件。

在Debian中(我不确定在其他发行版中是否相同),证书文件(.pem)存储在/etc/ssl/certs/中,因此,这是适用于我的代码:

1
2
3
import requests
verify='/etc/ssl/certs/cacert.org.pem'
response = requests.get('https://lists.cacert.org', verify=verify)

为了猜测pem文件选择了什么,我浏览了该URL并检查了哪个证书颁发机构(CA)生成了该证书。

编辑:如果您不能编辑代码(因为您正在运行第三个应用程序),您可以尝试将pem证书直接添加到/usr/local/lib/python2.7/dist-packages/requests/cacert.pem中(例如,将其复制到文件末尾)。


如果您不关心证书,只需使用verify=False

1
2
3
4
5
import requests

url ="Write your url here"

returnResponse = requests.get(url, verify=False)


经过数小时的调试后,我只能使用以下包使其正常工作:

1
2
requests[security]==2.7.0  # not 2.18.1
cryptography==1.9  # not 2.0

使用OpenSSL 1.0.2g 1 Mar 2016

没有这些包,verify=False就不起作用。

我希望这能帮助别人。


我也遇到了同样的问题。结果发现我没有在服务器上安装中间证书(只需将其附加到证书的底部,如下所示)。

网址:https://www.digicert.com/ssl-support/pem-ssl-creation.htm

确保已安装CA证书包:

1
sudo apt-get install ca-certificates

更新时间也可以解决此问题:

1
2
sudo apt-get install ntpdate
sudo ntpdate -u ntp.ubuntu.com

如果您使用的是自签名证书,则可能需要手动将其添加到系统中。


我和这个问题打了几个小时。

我试图更新请求。然后我更新了certifi。我将verify指向certifi.where()(代码默认情况下会这样做)。什么都没用。

最后,我将python的版本更新为python 2.7.11。我使用的是Python2.7.5,它与验证证书的方式有些不兼容。一旦我更新了python(以及其他一些依赖项),它就开始工作了。


请求模块中当前存在导致此错误的问题,出现在v2.6.2到v2.12.4(ATOW)中:https://github.com/kennethreitz/requests/issues/2573

解决此问题的方法是添加以下行:requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS'


如果请求调用隐藏在代码的某个深度,并且您不想安装服务器证书,那么,仅出于调试目的,可以对monkeypatch请求进行以下操作:

1
2
3
4
5
6
7
8
9
10
11
import requests.api
import warnings


def requestspatch(method, url, **kwargs):
    kwargs['verify'] = False
    return _origcall(method, url, **kwargs)

_origcall = requests.api.request
requests.api.request = requestspatch
warnings.warn('Patched requests: SSL verification disabled!')

不要在生产中使用!


正如@rafael almeida所提到的,您遇到的问题是由不受信任的SSL证书引起的。在我的例子中,我的服务器不信任SSL证书。为了在不影响安全性的情况下解决这个问题,我下载了证书,并将其安装在服务器上(只需双击.crt文件,然后安装证书…)。


我想去参加聚会已经太迟了,但我想为像我这样的流浪汉们贴上修正的标签!所以下面的内容在python 3.7.x上对我有所帮助

在终端中键入以下内容

1
pip install --upgrade certifi      # hold your breath..

再次尝试运行您的脚本/请求,看看它是否有效(我确信它还没有被修复!)。如果它不起作用,则尝试直接在终端中运行以下命令

1
open /Applications/Python\ 3.6/Install\ Certificates.command  # please replace 3.6 here with your suitable python version


在我的例子中,原因是相当微不足道的。

我知道ssl验证直到几天前才起作用,实际上是在另一台机器上工作。

我的下一步是比较验证工作的机器和不工作的机器之间的证书内容和大小。

这很快导致我确定"不正确"工作机器上的证书不好,一旦我用"良好"证书替换它,一切都很好。


我遇到了类似或相同的认证验证问题。我读到OpenSSL版本低于1.0.2,请求依赖于它,有时验证强证书时会遇到困难(请参见此处)。Centos7似乎使用了1.0.1e,这似乎有问题。

我不知道如何在CentOS上解决这个问题,所以我决定允许更弱的1024位CA证书。

1
2
import certifi # This should be already installed as a dependency of 'requests'
requests.get("https://example.com", verify=certifi.old_where())


如果从另一个包调用请求,则添加选项是不可行的。在这种情况下,向ca cert包中添加证书是一条直线路径,例如,我必须添加"startcom class 1 primary intermediate server ca",为此,我将根证书下载到startcom class 1.pem中。鉴于我的virtualenv名为caldav,我添加了证书:

1
2
cat StartComClass1.pem >> .virtualenvs/caldav/lib/python2.7/site-packages/pip/_vendor/requests/cacert.pem
cat temp/StartComClass1.pem >> .virtualenvs/caldav/lib/python2.7/site-packages/requests/cacert.pem

其中一个可能足够了,我没有检查


我必须从python 3.4.0升级到3.4.6

1
2
3
pyenv virtualenv 3.4.6 myvenv
pyenv activate myvenv
pip install -r requirements.txt