Python请求抛出SSLError


348

我正在研究一个简单的脚本,涉及CAS,jspring安全检查,重定向等。我想使用Kenneth Reitz的python请求,因为这是一项很棒的工作!但是,CAS需要通过SSL进行验证,因此我必须首先通过该步骤。我不知道想要什么Python请求吗?该SSL证书应该存放在哪里?

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

您可以共享更多代码信息吗?似乎缺少一个步骤。
TankorSmash 2012年

5
您应该始终提及需要帮助的软件版本。
Piotr Dobrogost 2012年

我在使用python 3.5龙卷风4.4时遇到了这个问题。HTTPRequest设置validate_cert = True,因此您可以将其设置为False进行处理
pan7an

Answers:


459

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

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

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

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

当然要运用判断力。正如在评论中提到的,这可能是为快速/一次性应用程序/脚本可以接受的,但真的不应该去制作软件

如果在特定情况下仅跳过证书检查是不可接受的,请考虑以下选项,最好的选择是将verify参数设置为字符串,该字符串是.pem证书文件的路径(应通过某种安全方法获取该字符串)手段)。

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

  • True:使证书根据库自身的可信证书颁发机构进行验证(注意:您可以通过Certifi库查看哪些根证书请求使用,Certifi库是从Requests:Certifi-Human Trust Database中提取的RC的信任数据库)。
  • False完全绕过证书验证。
  • CA_BUNDLE文件的路径,供请求用于验证证书。

来源:请求-SSL证书验证

还要看一下cert同一链接上的参数。


1
是的,当我在ubuntu中使用dotCloud时,出现了相同的“证书验证失败”。在“ /usr/local/lib/python2.6/dist-packages/dotcloud/client/client.py”中修改“ requests.session(headers = headers,hooks = hooks,verify = False)”之后,它就可以工作了。
diyism

2
这没有标记为正确,但是我可以验证它是否有效(与下面的答案相对)。
khalid13

40
@ khalid13:斧头可以作为头痛药(没有头-没有头痛)。这并不意味着以这种方式使用它是一个好主意。verify=False禁用主机的SSL证书检查。
jfs

24
@JFSebastian老实说,这取决于您在做什么。对于我的快速/一次性应用程序,这已经足够了。
khalid13

5
@diyism进行这样的更改听起来很不安全……
binki 2015年

111

关于SSL验证的请求文档中

就像网络浏览器一样,请求可以验证HTTPS请求的SSL证书。要检查主机的SSL证书,可以使用verify参数:

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

如果您不想验证自己的SSL证书,请输入 verify=False


4
好吧,我添加了verify = True,但仍然收到完全相同的错误。没变。还需要其他一些内容,但不知道可能是什么。
TedBurrows 2012年

我想我现在已经陷入了SSL疯狂。我将此添加到我的初始get ... get(url1,headers = headers,cert ='/ etc / pki / tls / cert.pem',verify = True,config = my_config)所以,现在我收到了此错误。requests.exceptions.SSLError:[Errno 336265225] _ssl.c:351:错误:140B0009:SSL例程:SSL_CTX_use_PrivateKey_file:PEM lib我不知道这是什么意思。
TedBurrows 2012年

14
如果您不想验证证书,只需设置verify = False,如果您具有自签名证书,则只需设置
Dirk

16
如果您具有自签名证书,请下载该证书,然后将verify设置为其文件名。设置verify = False没有任何借口。验证= '/路径/到/ cert.pem'
马蒂亚斯Urlichs

14
抱歉,Boud,我需要对此答案投反对票,因为请求无法像处理Web浏览器那样处理HTTPS请求。如果未在服务器上声明完整的SSL信任链(包括中间证书),并且需要下载额外的证书,您将收到上述SSL验证错误。Web浏览器将进行额外的下载,并且不会标记任何证书错误。这是Web浏览器和请求不同的一种方式。还有其他 请求会进行一些验证,但是不如浏览器好。
路易·克里门

53

要使用的CA文件名可以通过以下方式传递verify

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

如果使用,verify=Truerequests使用它自己的CA集,该CA集可能没有用于签署服务器证书的CA。


12
@ 9emE0iL18gxCqLT:为什么您认为所有系统都使用您提供的路径?requests可以打包以供您分发。运行python -mrequests.certs找出它指向的位置。
jfs

3
如果Python请求的cacert包已过期,如何更新它?
CMCDragonkai 2015年

5
您不应该cacert.pem从curl中使用它。它包含许多吊销的证书。签出Certifi
Kenneth Reitz

3
@KennethReitz:1- OP的请求使用失败(否则就没有问题了)2- cacert.pem是从Mozilla(通过cURL)提取的CA证书 -这只是一个示例(如果流行网站使用的CA列表) -browser不能用作示例,那么我不知道该怎么做)-答案是,如果默认列表失败,则可以传递自己的CA文件。
jfs

您可以同时使用客户端证书吗?我对此有问题。
user1156544

42

$ pip install -U requests[security]

  • 已在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.get(url, verify=False),如果已安装requests[security]其他功能。


7
固定 pip install -U requests[security] --no-cache两次,以及pip install certifi==2015.04.28
Aamir Abro

@alanjds如果我想配置python以信任某些ssl证书或禁用证书验证,但是要在环境中全局但不编辑源代码怎么办?例如,如果我下载了现有的Python实用程序(例如AWS CLI),并且想要信任证书或忽略那些工具的证书验证?
Howiecamp

@Howiecamp然后您可以通过jf-sebastian回答,我想:stackoverflow.com/a/12865159/798575
alanjds

@alanjds但是他的答案不是假设我正在编写代码和/或可以访问代码吗?我正在寻求在环境级别上实现这一目标。
Howiecamp

3
pip install --upgrade pip之前安装的请求安全包,以避免其他错误
文森特·克拉斯

40

使用aws boto3时遇到相同的问题,并且ssl证书验证失败的问题,通过查看boto3代码,我发现REQUESTS_CA_BUNDLE未设置,因此我通过手动设置解决了这两个问题:

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,我想将REQUESTS_CA_BUNDLE设置为~/.bashrc可以解决此问题(未经测试,因为我的aws-cli没有它就可以工作)。

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

2
这解决了我的问题!我在Mac上使用Charles Proxy调试一个对HTTPS API进行JSON调用的库。我按照指定的方式安装了Charless证书,并将其添加到钥匙串中,但是Python始终失败:SSLError:(“错误的握手:Error([('SSL例程','ssl3_get_server_certificate','证书验证失败')],)”)“ ,)为了解决这个问题,我最终听从了您有关添加REQUESTS_CA_BUNDLE并将我的钥匙串中的Charles证书导出为.pem文件的建议。现在,它起作用了!
mallyvai

谢谢,同样的问题是打开的提琴手
user565447 '16

@ user565447我正在尝试立即与Fiddler一起使用。是否应该将REQUESTS_CA_BUNDLE设置为Fiddler的证书工作?
Howiecamp

19

如果您有一个依赖的库requests并且不能修改验证路径(如pyvmomi),则必须找到cacert.pem与请求捆绑在一起的文件,然后在其中附加您的CA。这是找到cacert.pem位置的通用方法:

视窗

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

linux

#  (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与请求捆绑在一起确实非常烦人……尤其是您似乎没有先使用ca ca系统存储这一事实,并且在任何地方都没有记录。

更新

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

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

一百倍于此:密钥无法修改verify路径。
ghukill

如果您使用的是自签名证书怎么办?在这种情况下,CA将是什么?
user1114

微小的更新-对于python 3.6,应该为打印命令加上括号
-python

15

使用gspread会遇到相同的问题,这些命令对我有用:

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

这为我做到了。谢谢:)
alex-mcleod '16

4
这具有从较早版本的certifi重新安装可能吊销/不受信任的证书的缺点,不建议这样做。
dragon788 '16

如果由于某种原因您不得不使用早期版本的python 2.7,则降级certifi是唯一对我
有用的

15

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

import urllib3

urllib3.disable_warnings()

以及verify=Falsewith request.getpostmethod


12

我找到了解决类似问题的特定方法。这个想法是指向存储在系统上的cacert文件,并由另一个基于ssl的应用程序使用。

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

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(例如,将证书复制到文件末尾)。


2
调试python使用的CA_BUNDLE的相关文章
chk 2013年

用替换/usr/local/lib/python2.7/dist-packages/requests/cacert.pem为OS商店的符号链接怎么办?
CMCDragonkai 2015年

8

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

import requests

url = "Write your url here"

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

7

经过数小时的调试,我只能使用以下软件包来使其工作:

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

使用 OpenSSL 1.0.2g 1 Mar 2016

没有这些软件包将verify=False无法正常工作。

我希望这可以帮助别人。


5

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

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

确保已安装ca-certificates软件包:

sudo apt-get install ca-certificates

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

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

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


注意,这仅适用于通过apt-get进行请求安装,Debian / Ubuntu对其进行了修改,以使用系统证书。要求适当的船只带有自己的经过精心策划的CA捆绑包:certifi.io
Kenneth Reitz

根CA是否足够?为什么需要中间体?
蒂米

5

如果请求调用被埋在代码的深处,并且您不想安装服务器证书,则仅出于调试目的,可以对请求进行monkeypatch:

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!')

切勿在生产中使用!


4

我想参加聚会太晚了,但我想为像我这样的流浪者粘贴修复程序!所以以下内容在Python 3.7.x上为我解决了

在终端中输入以下内容

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

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

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

3

我为HOURS争取了这个问题。

我试图更新请求。然后,我更新了证书。我指出了对certifi.where()的验证(无论如何,代码默认情况下都会这样做)。没事。

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


如果您将OpenSSL更新到版本> 1.0.1,则可能是问题所在。看下面我的回答。 stackoverflow.com/a/44543047/1413201
蒂姆·卢德温斯基

从Python 2.7.9到2.7.10修复了这个问题。
crazystick '17

3

这类似于@ rafael-almeida的答案,但我想指出,从请求2.11+开始,没有3个值verify可以使用,实际上有4个:

  • True:根据请求的内部可信CA进行验证。
  • False完全绕过证书验证。(不建议)
  • CA_BUNDLE文件的路径。请求将使用它来验证服务器的证书。
  • 包含公共证书文件的目录的路径。请求将使用它来验证服务器的证书。

我剩下的答案是关于#4,如何使用包含证书的目录进行验证:

获取所需的公共证书并将其放置在目录中。

严格来说,您可能“应该”使用带外方法来获取证书,但是您也可以仅使用任何浏览器下载它们。

如果服务器使用证书链,请确保获取链中的每个证书。

根据请求文档,必须首先使用“ rehash”实用程序(openssl rehash)处理包含证书的目录。

(这需要openssl 1.1.1+,并且并非所有Windows openssl实施都支持rehash。如果openssl rehash不适合您,则可以尝试在https://github.com/ruby/openssl/blob/master上运行rehash ruby​​脚本。/sample/c_rehash.rb,尽管我还没有尝试过。

我在获取要求识别我的证书的请求时遇到了一些麻烦,但是在使用openssl x509 -outform PEM命令将证书转换为Base64 .pem格式后,一切工作正常。

您也可以只进行懒散的重新哈希处理:

try:
    # As long as the certificates in the certs directory are in the OS's certificate store, `verify=True` is fine.
    return requests.get(url, auth=auth, verify=True)
except requests.exceptions.SSLError:
    subprocess.run(f"openssl rehash -compat -v my_certs_dir", shell=True, check=True)
    return requests.get(url, auth=auth, verify="my_certs_dir")

2

目前,请求模块中存在一个导致此错误的问题,存在于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'


FWIW,它仍然存在于request == 2.13.0中。上述解决方法仍然可以解决此问题。
陶Szelei

1

如@Rafael Almeida所述,您遇到的问题是由不受信任的SSL证书引起的。就我而言,我的服务器不信任SSL证书。为了解决此问题而不损害安全性,我下载了证书并将其安装在服务器上(只需双击.crt文件,然后安装证书...)。


0

如果正在从另一个包中调用请求,则添加选项是不可行的。在那种情况下,将证书添加到cacert捆绑包是直接的方法,例如,我必须添加“ StartCom Class 1 Primary Intermediate Server CA”,为此,我将根证书下载到StartComClass1.pem中。鉴于我的virtualenv名为caldav,我添加了以下证书:

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

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


0

我遇到了相似或相同的认证验证问题。我读到的OpenSSL版本低于1.0.2,该请求有时取决于验证强证书的困难(请参阅此处)。CentOS 7似乎使用了1.0.1e,这似乎有问题。

我不确定如何在CentOS上解决此问题,因此我决定允许使用较弱的1024位CA证书。

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

我使用由ArcGIS安装的Python 2.7.10,没有安装证书模块。安装的请求模块的版本为2.11.1。
卢卡斯

0

我必须从Python 3.4.0升级到3.4.6

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

0

就我而言,原因是无关紧要的。

我知道SSL验证已经进行了几天,实际上是在另一台机器上工作。

我的下一步是比较正在验证的计算机和未进行验证的计算机之间的证书内容和大小。

这很快导致我确定“工作不正确”的计算机上的证书不好,一旦我将其替换为“好”证书,一切就很好了。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.