首先说明一点:SSLError的报错与Python版本无关(Python2.7和Python3都存在这个问题,解决办法一样)。
CA 证书
Requests 默认附带了一套它信任的根证书,来自于 Mozilla trust store。然而它们在每次 Requests 更新时才会更新。这意味着如果你固定使用某一版本的 Requests,你的证书有可能已经 太旧了。
从 Requests 2.4.0 版之后,如果系统中装了 certifi 包,Requests 会试图使用它里边的 证书。这样用户就可以在不修改代码的情况下更新他们的可信任证书。
为了安全起见,我们建议你经常更新 certifi!
前提:我司用的requests==2.15.1 certifi==2015.4.28
问题:我司调用第三方接口服务是以https请求出去的,我在测试服上mock了第三方,由于证书已被申请了,我这里只能生成一个自签的证书(详情见我另外一篇生成ssl证书)。原则上不能改变后端https请求方式及不增加多余代码,只能在我这里解决ssl证书认证问题。
解决思路一:
1、首先让测试服信任自签证书:
如果自己部署了一个CA系统,或者使用openssl生成了一个自签名的证书,如何让ubuntu系统信任这些证书呢
添加证书:
首先,复制pem格式的根证书,重命名为 .crt格式
然后,执行下边的命令
$sudo cp 证书路径.crt /usr/local/share/ca-certificates
$sudo update-ca-certificates
update-ca-certificates命令将PEM格式的根证书内容附加到/etc/ssl/certs/ca-certificates.crt ,而/etc/ssl/certs/ca-certificates.crt 包含了系统自带的各种可信根证书.
删除证书:
$sudo rm -f /usr/local/share/ca-certificates/证书名称.crt
$sudo update-ca-certificates
2、通过curl请求mock接口,https访问成功。
注意:
curl https://www.baidu.com 默认是验证系统证书的(https,不通过就会报错);
带证书访问curl --cacert /usr/local/share/ca-certificates/xxx.crt -d "" https://www.baidu.com;
3、通过server发出的请求一直500,原因是requests库没有信任我的自签证书。
经查,从 Requests 2.4.0 版之后,如果系统中装了 certifi 包,Requests 会试图使用它里边的 证书。因此可以通过修改certifi证书库,新增自签证书。
附查找路径方法:
import certifi
certifi.where()
'/Users/xxx/.virtualenvs/server_env_py3/lib/python3.5/site-packages/certifi/cacert.pem'
添加后,直接发出https请求即可,不用重启服务。
解决思路二:(不建议使用)
找到requests默认信任的证书路径:
from requests.utils import DEFAULT_CA_BUNDLE_PATH
print(DEFAULT_CA_BUNDLE_PATH)
1、修改requests源码,改变证书信任路径,源码如下:
DEFAULT_CA_BUNDLE_PATH = certs.where()
2、请求mock接口之前设置下环境变量:
REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt # ca-bundle.crt
export REQUESTS_CA_BUNDLE
注:关于解决思路问题,绕了个弯。由于请求是requests发出去的,应该一开始就查看底层代码和相关文档。不应该把时间放在服务器认证上面,思路应该是自上而下的,记录一下。
参考:
requests:http://docs.python-requests.org/zh_CN/latest/user/advanced.html
certifi:https://pypi.python.org/pypi/certifi/
https://stackoverflow.com/questions/27835619/urllib-and-ssl-certificate-verify-failed-error
https://stackoverflow.com/questions/10667960/python-requests-throwing-sslerror