为啥 python SSL 模块无法验证 graph.facebook.com 证书?

Posted

技术标签:

【中文标题】为啥 python SSL 模块无法验证 graph.facebook.com 证书?【英文标题】:Why can't python SSL module verify graph.facebook.com certificate?为什么 python SSL 模块无法验证 graph.facebook.com 证书? 【发布时间】:2011-10-08 22:51:18 【问题描述】:

通过将我的浏览器指向https://graph.facebook.com/me,我得到一个加密的 HTTPS 连接,证书链是:

DigiCert 高保证 EV 根 CA(根) DigiCert 高保证 CA-3 *.facebook.com

所以我从https://www.digicert.com/digicert-root-certificates.htm下载了根证书(我也从浏览器导出了它,差异显示它们是一样的),并尝试使用Python内置的SSL模块来验证连接的真实性到graph.facebook.com。

我刚刚执行了示例 http://docs.python.org/library/ssl.html#client-side-operation,将 ca_cert 替换为“DigiCertHighAssuranceEVRootCA.crt”,并将地址替换为 graph.facebook.com。连接尝试失败,但出现以下异常:

ssl.SSLError: [Errno 1] _ssl.c:499: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

如果我针对 ev-root.digicert.com(这是 DigiCert 提供的用于测试客户端是否可以验证其证书的地址)尝试相同的代码和证书,则一切正常。通过浏览器,我可以验证此连接中使用的链是:

DigiCert 高保证 EV 根 CA(根) DigiCert 高保证 EV CA-1 ev-root.digicert.com

通过运行 ssl.get_server_certificate(('graph.facebook.com', 443)) 我的浏览器获得了与“*.facebook.com”相同的证书,这意味着 Python 代码和我的浏览器都获得了相同的证书进行验证。

为什么 Chrome 可以使用给定的根证书验证 graph.facebook.com,Python 可以使用相同的根证书验证另一个站点,但 Python 不能验证 graph.facebook.com?

【问题讨论】:

【参考方案1】:

我从 OpenSSL 邮件列表中得到了答案。似乎“DigiCert High Assurance EV Root CA”在自签名之前由另一个证书颁发机构签名。现在有两个版本的证书。一个与 SSL 实现捆绑在一起,由 DigiCert 提供下载,它是自签名的,可用作根 CA 来验证它签署的其他证书。另一个版本是 Facebook 的服务器在 SSL 握手过程中返回的版本,由一些 Entrust 证书签名。两者具有相同的公钥和 keyid。

NSS,Firefox 和 Chrome 的 SSL 实现,显然正确地遵循了 X.509 规范并忽略了服务器发送的链中的最后一个证书,并使用自己的可信版本“DigiCert High Assurance EV Root CA”来验证链。 Python 的实现是通过 OpenSSL,它使用主机提供的证书验证“DigiCert High Assurance CA-3”,然后尝试验证最后一个。由于它是由其他 CA 签名的,并且我没有提供该证书,所以它失败了。我不认为这种行为是正确的,因为由于我已经信任链中间的证书,理论上我不需要检查其余部分。

我的解决方案是向 ssl 模块提供验证“DigiCert High Assurance EV Root CA”的 Entrust 证书。

【讨论】:

【参考方案2】:

如果您在代理后面工作,您可能还想在浏览器中打开https://graph.facebook.com,并从那里检查证书路径。您的代理可能充当网站证书的颁发者。在这种情况下,识别您的代理证书,将其提取到 pem 文件中并将内容附加到 Python 证书 cacert.pem 证书。

【讨论】:

以上是关于为啥 python SSL 模块无法验证 graph.facebook.com 证书?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Ruby 无法验证 SSL 证书?

[转]关于python出现ssl:certificate_verify_failed问题

Python 无法导入 ssl 模块

Python - [SSL: CERTIFICATE_VERIFY_FAILED] 证书验证失败:无法获取本地颁发者证书 (_ssl.c:1091)

Python3中无法导入ssl模块的解决办法

pip 总是无法通过 ssl 验证