Python请求 - 如何使用系统ca证书(debian / ubuntu)?

时间:2017-03-23 16:44:55

标签: python ssl debian python-requests debian-based

我已经在debian的/usr/share/ca-certificates/local中安装了自签名的root ca证书,并使用sudo dpkg-reconfigure ca-certificates安装了它们。此时true | gnutls-cli mysite.local很高兴,true | openssl s_client -connect mysite.local:443很高兴,但python2和python3请求模块坚持认为它对证书不满意。

python2:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/local/lib/python2.7/site-packages/requests/api.py", line 70, in get
    return request('get', url, params=params, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/requests/api.py", line 56, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 488, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 609, in send
    r = adapter.send(request, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/requests/adapters.py", line 497, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: ("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",)

python3

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/usr/local/bin/python3.5/site-packages/requests/api.py", line 70, in get
    return request('get', url, params=params, **kwargs)
  File "/usr/local/bin/python3.5/site-packages/requests/api.py", line 56, in request
    return session.request(method=method, url=url, **kwargs)
  File "/usr/local/bin/python3.5/site-packages/requests/sessions.py", line 488, in request
    resp = self.send(prep, **send_kwargs)
  File "/usr/local/bin/python3.5/site-packages/requests/sessions.py", line 609, in send
    r = adapter.send(request, **kwargs)
  File "/usr/local/bin/python3.5/site-packages/requests/adapters.py", line 497, in send
    raise SSLError(e, request=request)
requests.exceptions.SSLError: ("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",)

为什么python会忽略系统ca-certificates包,我该如何集成它?

4 个答案:

答案 0 :(得分:41)

来自https://stackoverflow.com/a/33717517/1695680

要使python请求使用系统ca-certificates包,需要告诉它在自己的嵌入式包上使用它

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

请求将其捆绑包嵌入此处,以供参考:

/usr/local/lib/python2.7/site-packages/requests/cacert.pem
/usr/lib/python3/dist-packages/requests/cacert.pem

答案 1 :(得分:2)

我最近挣扎了一个星期左右。我终于找到了在Python中验证自签名或私有签名证书的方法。您需要创建自己的证书包文件。每次更新库或向系统证书库添加任何内容时,无需更新模糊的证书包。

首先运行之前运行的openssl命令,但添加-showcerts。 openssl s_client -connect mysite.local:443 -showcerts这将为您提供长输出,在顶部您将看到整个证书链。通常,这意味着三个证书,即网站的证书,中间证书和该订单中的根证书。我们需要将根证书和中间证书以相反的顺序放入下一个文件中。

将最后一个证书(根证书)复制到新的文本文件中。抓住之间的东西,包括:

-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

将中间证书(也称为中间证书)复制到根证书下的新文本文件中。再次,抓住开始和结束证书行以及其间的所有内容。

将此文本文件保存到Python脚本所在的目录中。我的建议是将其称为CertBundle.pem。 (如果您为其指定了不同的名称,或将其放在文件夹结构中的其他位置,请确保验证行反映了该内容。)更新脚本以引用新证书包:

response = requests.post("https://www.example.com/", headers=headerContents, json=bodyContents, verify="CertBundle.pem")

就是这样。如果您只有根证书或只有中间证书,那么Python无法验证整个证书链。但是,如果您在所创建的证书包中包含这两个证书,那么Python可以验证中间人是否由根签名,然后当它访问网站时,它可以验证网站的证书是否由中间证书签名

编辑:修复了证书包的文件扩展名。另外,修正了一些语法错误。

答案 2 :(得分:2)

requests 使用 certifi 作为默认的根证书包,它内置了很多好的 CA 但无法修改。

Debian(和 Ubuntu)维护者改变了 certifi 与默认行为不同的行为:

def where():
    return "/etc/ssl/certs/ca-certificates.crt"

因此,如果您使用 apt 安装的 requestscertifi,则没有问题。

但是 pip3 在虚拟环境中安装了 certifi 使用内置 CA。所以无法使用update-ca-certificates机制。除了在应用程序代码中手动指定根证书(如果 request 通过 3rd 方接口间接调用,这可能是不可能的),它还可以覆盖环境变量 REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt 以模拟 Debianized 行为。

答案 3 :(得分:0)

我的两分钱

感谢其他answer的帮助,我检查了实际的请求代码,我发现您不必使用env变量,而只需在请求中设置“验证”参数即可:< / p>

requests.get("https://whatever", verify="/my/path/to/cacert.crt", ...)

它也是documented,尽管我只能在发现之后找到文档(并且pypi项目指向doc的无效链接):D