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

时间:2011-10-08 22:51:19

标签: python facebook ssl https ssl-certificate

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

  • DigiCert高保证EV根CA(根)
  • DigiCert High Assurance 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 High Assurance 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?

2 个答案:

答案 0 :(得分:4)

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

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

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

答案 1 :(得分:0)

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