Python在没有咨询系统CA捆绑的情况下抛出SSL证书验证错误?

时间:2017-04-07 18:25:07

标签: python ssl fedora-25

两个大致相同的系统(都运行Fedora 25,两者都安装了类似的软件包版本),一个系统失败,出现SSL证书验证错误,而另一个系统没有。也就是说,如果我跑:

import requests
r = requests.get('https://insidehost.corp.example.com')

它运作的一个系统,而另一个系统失败:

requests.exceptions.SSLError: ("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",)

起初我认为我只是缺少必要的CA证书,但在strace下运行python表明,在失败的系统上,python 从不尝试打开ca包。也就是说,在有效的系统上:

strace -e trace=open,stat python testscript.py |& grep /etc/pki

仅收益:

open("/etc/pki/tls/legacy-settings", O_RDONLY) = -1 ENOENT (No such file or directory)
stat("/etc/pki/tls/certs/ca-bundle.crt", {st_mode=S_IFREG|0444, st_size=257079, ...}) = 0
open("/etc/pki/tls/certs/ca-bundle.crt", O_RDONLY) = 4

但是对于失败的系统产量:

open("/etc/pki/tls/legacy-settings", O_RDONLY) = -1 ENOENT (No such file or directory)

此外,在失败的系统上使用python3运行相同的测试脚本......有效!

在这两种情况下,python都来自/usr/bin/python python-2.7.13-1.fc25.x86_64。两个系统都没有设置任何*_CA_BUNDLE环境变量。

1 个答案:

答案 0 :(得分:0)

经过一些额外的调查,我已经弄明白了,我想我会在这里发布解决方案,因为它不一定显而易见。

requests模块包含自己的证书捆绑包,如果找不到另一个要使用的证书捆绑包,它将依赖于该证书捆绑包。它在request / certs.py:

中查找证书包的方式如下所示
try:
    from certifi import where
except ImportError:
    def where():
        """Return the preferred certificate bundle."""
        # vendored bundle inside Requests
        return os.path.join(os.path.dirname(__file__), 'cacert.pem')

您可以通过运行以下内容查看此结果:

$ python -m requests.certs
/etc/pki/tls/certs/ca-bundle.crt

从上面的代码中可以看出,requests使用certifi模块找到合适的包。在发生故障的系统上,certifi模块已通过pip而不是使用系统软件包安装,这意味着它缺少适当的配置。

解决方案是yum install python2-certifi