抛出SSLError的Python请求

时间:2012-05-19 18:45:21

标签: python ssl python-requests urllib3

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

24 个答案:

答案 0 :(得分:357)

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

与前一条评论中提到的@dirk一样,最快修复正在设置verify=False

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

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

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

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

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

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

来源:Certifi - Trust Database for Humans

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

答案 1 :(得分:102)

来自请求documentation on SSL verification

  

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

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

如果您不想验证SSL证书,请创建verify=False

答案 2 :(得分:46)

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

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

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

答案 3 :(得分: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)上,&#34;安全&#34;引入了额外内容,使用certifi包(如果有)。

目前(2016-09)主要版本是2.11.1,效果不错没有 verify=False。如果安装了requests.get(url, verify=False)个额外内容,则无需使用requests[security]

答案 4 :(得分:25)

我在使用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

答案 5 :(得分:15)

如果你有一个依赖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';)"

答案 6 :(得分:13)

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

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

答案 7 :(得分:11)

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

import urllib3

urllib3.disable_warnings()
带有verify=Falserequest.get方法的

post

答案 8 :(得分: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文件的选择,我浏览了网址,并检查哪个证书颁发机构(CA)已生成证书。

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

答案 9 :(得分:9)

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

import requests

url = "Write your url here"

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

答案 10 :(得分: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无效。

我希望这有助于某人。

答案 11 :(得分: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

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

答案 12 :(得分:3)

我为HOURS打了这个问题。

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

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

答案 13 :(得分: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'

答案 14 :(得分:2)

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

永远不要在生产中使用!

答案 15 :(得分:1)

其他人指出,此问题“是由不受信任的SSL证书引起的”。我的答案基于top-rated answerthis answer

您可以使用curl测试证书:

curl -vvI https://example.com

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

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

我的问题是因为我仅使用站点的证书,而不使用中间(也称为链)证书。

如果使用“让我们加密”,则应使用fullchain.pem文件,而不是cert.pem

答案 16 :(得分:1)

这类似于@ rafael-almeida的答案,但我想指出,从请求2.11+开始,verify不能接受3个值,实际上有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/sample/c_rehash.rb上运行rehash ruby​​脚本我还没有尝试过。)

我在获取识别证书的请求时遇到了一些麻烦,但是在我使用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")

答案 17 :(得分: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

答案 18 :(得分:1)

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

答案 19 :(得分:0)

我必须从Python 3.4.0升级到3.4.6

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

答案 20 :(得分: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())

答案 21 :(得分:0)

在我看来,原因很简单。

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

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

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

答案 22 :(得分: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

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

答案 23 :(得分:-1)

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

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

警告:不使用HTTPS通常不是一个好主意。参见Why HTTPS for Everything? Why HTTPS matters