Httplib2 SSL 错误

10
今天我遇到了一个有趣的问题。
我正在使用foursquare推荐的Python库httplib2 raise。
SSLHandshakeError(SSLError(1, '_ssl.c:504: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed'),) 

尝试请求OAuth令牌时

response, body = h.request(url, method, headers=headers, body=data)

_process_request_with_httplib2 function

有人知道为什么会出现这种情况吗?


4
我很确定SSL证书验证失败了 :-D - Savir
4个回答

23
如果你知道你要访问的网站是一个“好人”,你可以尝试用以下方式创建你的“打开器”:
import httplib2
if __name__ == "__main__":
    h = httplib2.Http(".cache", disable_ssl_certificate_validation=True)
    resp, content = h.request("https://site/whose/certificate/is/bad/", "GET")

(有趣的部分是disable_ssl_certificate_validation=True

来自文档: http://bitworking.org/projects/httplib2/doc/html/libhttplib2.html#httplib2.Http

编辑01:

既然您的问题实际上是为什么会发生这种情况,您可以查看 thisthis

编辑02:

考虑到这个答案被访问的人比我预期的要多,我想解释一下在何时禁用证书验证可能会有用。

首先,简单介绍一下这些证书工作的背景。在上面提供的链接中有很多信息,但是无论如何,它都在这里。

SSL证书需要由一个知名的(至少对你的浏览器来说是知名的)证书颁发机构进行验证。通常情况下,你可以从这些机构中购买整个证书(SymantecGoDaddy...)
总的来说,思路是这样的:这些证书颁发机构(CA)会给你一个包含CA信息的证书。你的浏览器有一个知名CA列表,所以当你的浏览器接收到一个证书时,它会做出类似这样的判断:"HmmmMMMmmm....[浏览器在这里做出怀疑的表情]...我收到了一份证书,它说它是由Symantec验证的。我认识那个“Symantec”家伙吗?[浏览器然后查找其知名CA列表并检查Symantec]哦,是的!我知道。好的,证书是有效的! 如果您点击浏览器地址栏旁边的小锁,就可以自己查看相关信息:

Chrome certificate information

然而,有些情况下,您只想测试HTTPS,并使用几个命令行工具创建自己的证书颁发机构,然后使用该“自定义”CA签署刚生成的“自定义”证书,对吗?在这种情况下,您的浏览器(顺便说一下,在问题中是httplib2.Http)将不会将您的“自定义”CA列入信任的CA列表中,因此它会说证书无效。信息仍将以加密方式传输,但浏览器告诉您的是,它不完全相信正在加密传输到您所假定的位置。
例如,假设您创建了一组自定义密钥和CA,并按照本教程中的说明为您的localhostFQDN创建了所有繁琐的东西,并且您的CA证书文件位于当前目录中。您可以很好地在https://localhost:4443上运行服务器,使用您的自定义证书等等。现在,您的CA证书文件位于当前目录中,在文件./ca.crt中(与您的Python脚本将要运行的相同目录中)。您可以像这样使用httplib2
h = httplib2.Http(ca_certs='./ca.crt')
response, body = h.request('https://localhost:4443')
print(response)
print(body)

...那么您就不会再看到警告了。为什么呢?因为您告诉 httplib2 去查找 CA 证书到 ./ca.crt)

然而,由于 Chrome(以浏览器为例)并不知道这个 CA 的证书,它会认为它是无效的:

enter image description here

此外,证书会过期。有可能你在一家使用SSL加密内部网站的公司工作。它可以正常运行一年,然后你的浏览器开始发出警告。你找到负责安全的人,问道:“嘿!我在这里收到了这个警告!发生了什么?”答案很可能是:“哦,天哪!我忘记更新证书了!没关系,从现在开始接受它,直到我修复它为止。”(真实故事,尽管我收到的回答中有脏话:-D

3
这真的不是一个好主意 - 你应该真正弄清楚为什么验证失败。通过禁用验证,你实质上删除了检测许多中间人攻击的能力,其中某人想要冒充上游 Foursquare 服务器 - 你甚至无法检测到他们生成自签名证书的简单情况。 - javanix
1
注意:要禁用证书验证,只需要这样 h = httplib2.Http(disable_ssl_certificate_validation=True) - Iurii Tkachenko
@javanix,因此如果您知道您要获取的网站是“好人”... - Savir
对于这个解决方案所获得的赞数和页面浏览量,我只能 facepalm。这个建议显示出缺乏对证书验证目的的理解,应该从答案列表中删除。这不是关于信任实际站点,而是关于信任站点之间的所有内容。正如 @javanix 提到的那样,它是为了保护客户免受中间人攻击。 - deltaray
作为这个答案的原始发布者,我想邀请@deltaray阅读我所做的第二次编辑,并解释一下如果您需要快速访问一个使用自签名证书或忘记更新其证书的网站时,您将如何克服这些问题。因为这在现实生活中经常发生。 - Savir

13

最近版本的httplib2默认使用其自己的证书存储。

# Default CA certificates file bundled with httplib2.
CA_CERTS = os.path.join(
     os.path.dirname(os.path.abspath(__file__ )), "cacerts.txt")

如果您使用的是ubuntu/debian操作系统,您可以明确传递系统证书文件的路径,如下:

httplib2.HTTPSConnectionWithTimeout(HOST, ca_certs="/etc/ssl/certs/ca-certificates.crt")

3
也许是这种情况: 我遇到了同样的问题,调试 Google Lib 后发现问题原因是我使用了旧版本的 httplib2(0.9.2)。当我更新到最新版(0.14.0)时就解决了。
如果你已经安装了最新版,请确保某个库未在其依赖项中安装了旧版本的 httplib2。

0
当您在使用自签名证书时遇到此错误,通常发生在企业代理内部时,您可以使用环境变量将httplib2指向您的自定义证书包。例如,当您不想(或无法)修改代码以传递ca_certs参数时,可以这样做。
当您不想修改系统证书存储以附加您的CA证书时,也可以这样做。
export HTTPLIB2_CA_CERTS="\path\to\your\CA_certs_bundle"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接