我正在编写一个简单的脚本,涉及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
如果你有一个依赖于请求的库,你不能修改验证路径(比如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')";
我认为你有几种方法可以解决这个问题。我提到了以下5种方法:
你可以为每个请求定义上下文,并在每个请求上传递上下文,如下所示:
import certifi
import ssl
import urllib
context = ssl.create_default_context(cafile=certifi.where())
result = urllib.request.urlopen('https://www.example.com', context=context)
或在环境中设置证书文件。
import os
import certifi
import urllib
os.environ["REQUESTS_CA_BUNDLE"] = certifi.where()
os.environ["SSL_CERT_FILE"] = certifi.where()
result = urllib.request.urlopen('https://www.example.com')
创建默认的https上下文方法:
import certifi
import ssl
ssl._create_default_https_context = lambda: ssl.create_default_context(cafile=certifi.where())
result = urllib.request.urlopen('https://www.example.com')
如果您使用Linux机器,生成新的证书并导出指向证书目录的环境变量,则可以修复该问题。
$ sudo update-ca-certificates --fresh
$ export SSL_CERT_DIR=/etc/ssl/certs
或如果您使用Mac机器,生成新的证书
$ cd "/Applications/$(python3 --version | awk '{print $2}'| awk -F. '{print "Python " $1"."$2}')"
$ sudo "./Install Certificates.command"
您遇到的问题是由不受信任的SSL证书引起的。
就像之前的评论中提到的@dirk一样,最快的修复方法是设置verify=False:
requests.get('https://example.com', verify=False)
请注意,这将导致无法验证证书。这将使您的应用程序面临安全风险,例如中间人攻击。
当然,要有判断力。正如评论中提到的,这对于快速/一次性应用程序/脚本可能是可以接受的,但真的不应该用于生产软件。
如果仅仅跳过证书检查在您的特定上下文中是不可接受的,请考虑以下选项,最好的选项是将verify参数设置为一个字符串,该字符串是证书的.pem文件的路径(您应该通过某种安全方法获取该文件)。
因此,从2.0版本开始,verify形参接受以下值,并具有各自的语义:
True:使证书针对库自己的受信任证书颁发机构进行验证(注意:您可以通过Certifi库查看请求使用的根证书,Certifi库是从Requests: Certifi - trust database for Humans中提取的rc的信任数据库)。
False:完全跳过证书验证。
请求用来验证证书的CA_BUNDLE文件的路径。
来源:请求- SSL证书验证
还可以查看同一链接上的cert参数。
如果你有一个依赖于请求的库,你不能修改验证路径(比如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')";
有些服务器没有Letsencrypt的可信根证书。
例如,假设下面的url指向的服务器受到Letsencrypt SSL的保护。
requests.post(url, json=data)
此请求可能使用[SSL: CERTIFICATE_VERIFY_FAILED]失败,因为请求服务器没有Letsencrypt的根证书。
当发生这种情况时,请从下面的链接下载活动自签名的“pem”证书。
https://letsencrypt.org/certificates/。(在撰写本文时,ISRG根X1处于活动状态)
现在,在verify参数中使用它,如下所示。
requests.post(url, json=data, verify='path-to/isrgrootx1.pem')