如何使用urllib2.urlopen检查(不绕过)SSL证书?

问题描述 投票:0回答:1

我正在使用Python 2.7.13。我正在尝试连接到https://www.python.org/并使用urllib2.urlopen验证其证书。我在此过程中收到“SSL:CERTIFICATE_VERIFY_FAILED”错误,当我尝试谷歌问题时,我似乎得到了如何绕过此安全检查的答案。但我不希望我的代码绕过它,我希望它使用证书。这是我的代码失败:

import urllib2
from contextlib import closing
import ssl

ctx = ssl.create_default_context(purpose = ssl.Purpose.SERVER_AUTH, cafile = 'www.python.org.crt')
request = urllib2.Request('https://www.python.org/')
# Produces URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:661)>
with closing(urllib2.urlopen(request, context = ctx)) as response:
    print response.read()

cafile = 'www.python.org.crt'是一个PEM格式的文​​件,正确地从-----BEGIN CERTIFICATE-----开始。我使用https://www.python.org/this instruction导出它并将其放入脚本的工作文件夹中。

python-2.7 ssl-certificate urllib2
1个回答
0
投票

从文档:https://docs.python.org/2/library/ssl.html#ssl._https_verify_certificates

从Python 2.7.9开始,httplib和使用它的模块(例如urllib2和xmlrpclib)默认验证在建立客户端HTTPS连接时收到的远程服务器证书。此默认验证检查证书是否由系统信任库中的证书颁发机构签名,并且所显示证书上的公用名(或主题备用名)与请求的主机匹配。

所以你不需要任何特殊的东西来验证证书。您可以看到,因为您有验证失败,这表明您正在进行验证。

那么为什么你没有成功验证?答案就在于您使用咖啡馆。 cafile参数采用一个文件覆盖系统默认的可信证书库。但要理解可信证书的重要一点,验证过程不是检查主机是在受信任的商店中,而是在受信任的商店中签名但是是证书。因此,您不需要传递实际的服务器证书,您将从python.org的证书供应商(撰写本文时的digicert)传递证书。

但实际上您甚至不需要这样做,因为系统应该附带来自许多供应商的大量可信证书。这些供应商在某种程度上受到审核(意见因程度而异 - 现在这个主题有所不同),如果将cafile参数留空,python的库将根据此设置进行验证。

所以你找到了

>>> ctx = ssl.create_default_context(purpose = ssl.Purpose.SERVER_AUTH, cafile = '/tmp/python.org.cert')    
>>> urllib2.urlopen("https://www.python.org/", context = ctx)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/urllib2.py", line 154, in urlopen
    return opener.open(url, data, timeout)
  File "/usr/lib/python2.7/urllib2.py", line 429, in open
    response = self._open(req, data)
  File "/usr/lib/python2.7/urllib2.py", line 447, in _open
    '_open', req)
  File "/usr/lib/python2.7/urllib2.py", line 407, in _call_chain
    result = func(*args)
  File "/usr/lib/python2.7/urllib2.py", line 1241, in https_open
    context=self._context)
  File "/usr/lib/python2.7/urllib2.py", line 1198, in do_open
    raise URLError(err)
urllib2.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:661)>

失败了,但是这个:

>>> ctx = ssl.create_default_context(purpose = ssl.Purpose.SERVER_AUTH,)                                    
>>> urllib2.urlopen("https://www.python.org/", context = ctx)                                               
<addinfourl at 140556044048504 whose fp = <socket._fileobject object at 0x7fd5c1127b50>>

作品。

最后,我想指出httplib和http.client(在python 3中),它们对于这类事情来说是更清晰的接口。

© www.soinside.com 2019 - 2024. All rights reserved.