抛出SSLError的Python请求

问题描述 投票:272回答:21

我正在编写一个涉及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
python ssl python-requests urllib3
21个回答
360
投票

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

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

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

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

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

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

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

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

资料来源:Requests - SSL Cert Verification

另请参阅同一链接上的cert参数。


9
投票

如果你不打扰证书只需使用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

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


3
投票

我为HOURS打了这个问题。

我试图更新请求。然后我更新了certifi。我指向验证certifi.where()(默认情况下代码执行此操作)。没有任何效果。

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


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'


2
投票

如果请求调用被隐藏在代码深处某个地方并且您不想安装服务器证书,那么,仅仅出于调试目的,可以对monkeypatch请求进行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!')

永远不要用于生产!


1
投票

正如@Rafael Almeida所提到的,您遇到的问题是由不受信任的SSL证书引起的。就我而言,我的服务器不接受SSL证书。为了解决这个问题而不影响安全性,我downloaded the certificate,并将其安装在服务器上(只需双击.crt文件然后安装证书...)。


1
投票

我猜这个派对太迟了但是我想把像我这样的流浪者的修补程序粘贴一下!所以下面的内容在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

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,请求取决于有时无法验证强证书(请参阅here)。 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())

102
投票

从请求documentation on SSL verification

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

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

如果您不想验证您的SSL证书,请制作verify=False


0
投票

我不得不从Python 3.4.0升级到3.4.6

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

0
投票

在我的情况下,原因是相当微不足道的。

我知道SSL验证在几天前就开始工作了,并且实际上是在另一台机器上运行。

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

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


47
投票

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

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

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


33
投票

$ 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]


26
投票

我在使用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,我想在~/.bashrc中设置REQUESTS_CA_BUNDLE将解决这个问题(未经测试,因为我的aws-cli在没有它的情况下工作)。

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

17
投票

如果您有一个依赖于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-bundle位置的情况下,您还可以将ca-bundle位置明确设置为主机范围的ca-bundle:

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

13
投票

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

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

12
投票

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

import urllib3

urllib3.disable_warnings()

verify=Falserequest.getpost方法


10
投票

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.