438

我正在编写一个涉及 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
4

26 回答 26

595

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

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

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

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

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

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

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

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

来源:请求 - SSL 证书验证

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

于 2012-10-12T18:19:07.240 回答
124

从关于 SSL 验证的请求文档:

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

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

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

于 2012-05-19T19:20:07.677 回答
59

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

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

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

于 2012-10-12T18:38:46.953 回答
53

我在使用 aws boto3 时遇到了同样的问题和 ssl certificate verify failed 问题,通过查看 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
于 2015-11-15T07:47:16.803 回答
48

$ 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]额外的。

于 2016-09-19T18:57:31.920 回答
31

如果您有一个依赖的库requests并且您无法修改验证路径(例如 with 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 与 request 捆绑在一起真的很烦人……尤其是您似乎没有首先使用系统 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')";
于 2016-03-04T08:38:52.793 回答
21

正如其他人指出的那样,这个问题“是由不受信任的 SSL 证书引起的”。我的答案是基于评价最高的答案这个答案

您可以使用以下方法测试证书curl

curl -vvI https://example.com

如果返回错误,您有 3 个选项:

  1. 为了快速修复,您不能验证证书:
requests.get('https://example.com', verify=False)
  1. 将路径传递到 CA_BUNDLE 文件或具有受信任 CA 证书的目录:
requests.get('https://example.com', verify='/path/to/certfile')
  1. 如果您有权访问,请修复 Web 服务器证书。

我的问题是因为我只使用了我网站的证书,而不是中间(又名链)证书。

如果你使用 Let's Encrypt,你应该使用fullchain.pem文件,而不是cert.pem.

于 2020-11-20T15:09:57.927 回答
17

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

import urllib3

urllib3.disable_warnings()

and verify=Falsewith request.getorpost方法

于 2015-11-03T07:42:57.610 回答
15

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

sudo pip uninstall -y certifi
sudo pip install certifi==2015.04.28
于 2016-02-16T04:53:27.560 回答
13

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

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

于 2013-04-18T14:29:46.447 回答
8

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

import requests

url = "Write your url here"

returnResponse = requests.get(url, verify=False)
于 2015-05-21T12:01:25.640 回答
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是行不通的。

我希望这可以帮助别人。

于 2017-07-20T20:10:35.633 回答
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

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

于 2014-06-13T19:19:33.897 回答
5

我想派对太晚了,但我想为像我这样的流浪者粘贴修复程序!因此,在 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
于 2018-11-29T11:32:11.540 回答
5

如果请求调用隐藏在代码深处并且您不想安装服务器证书,那么,仅出于调试目的,可以对请求进行猴子补丁:

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

切勿在生产中使用!

于 2017-08-29T06:06:20.120 回答
4

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

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

我的其余答案是关于#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")
于 2019-10-10T20:44:41.260 回答
3

我与这个问题斗争了几个小时。

我试图更新请求。然后我更新了证书。我将 verify 指向 certifi.where() (无论如何,代码默认情况下都会这样做)。没有任何效果。

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

于 2016-05-06T21:13:57.057 回答
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'

于 2017-01-15T20:10:47.843 回答
1

有些服务器没有 Letsencrypt 的受信任根证书。

例如,假设下面 url 指向的服务器受 Letsencrypt SSL 保护。

requests.post(url, json=data)

此请求可能会因 [SSL: CERTIFICATE_VERIFY_FAILED] 而失败,因为请求服务器没有 Letsencrypt 的根证书。

发生这种情况时,请从下面的链接下载活动的自签名“pem”证书。

https://letsencrypt.org/certificates/。(截至撰写本文时,活跃的 ISRG Root X1 )

现在,在验证参数中使用它,如下所示。

requests.post(url, json=data, verify='path-to/isrgrootx1.pem')
于 2021-10-20T20:09:34.757 回答
1

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

于 2017-06-14T11:07:43.137 回答
1

就我而言,原因相当微不足道。

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

我的下一步是比较正在验证的机器和没有验证的机器之间的证书内容和大小。

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

于 2019-04-30T11:59:06.660 回答
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

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

于 2015-08-03T17:29:21.867 回答
0

我不得不从 Python 3.4.0 升级到 3.4.6

pyenv virtualenv 3.4.6 myvenv
pyenv activate myvenv
pip install -r requirements.txt
于 2018-03-07T23:22:18.590 回答
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())
于 2017-07-11T13:26:59.380 回答
0

我找到了修复它的答案:

import ssl
import certifi
import urllib.request

url = "https://www.google.com/"
html = urllib.request.urlopen(url, context=ssl.create_default_context(cafile=certifi.where()))

不过,我不知道它做了什么。

于 2021-10-02T06:41:00.723 回答
-2

这只是您尝试解决问题的另一种方法。

如果您输入“www.example.com”,请求就会对您大喊大叫。如果您输入“https://www.example.com”,则会收到此错误。因此,如果您不需要 https,则可以通过将“https”更改为“http”来避免错误。例如。“http://www.example.com”

警告:不使用 HTTPS 通常不是一个好主意。请参阅为什么使用 HTTPS? 为什么 HTTPS 很重要

于 2020-09-02T08:09:26.643 回答