我正在尝试让Python urllib.request.urlopen(url, ca*)
执行证书检查,但忽略主机名不匹配。
(这是必需的,因为可以通过公共IP,私有IP,主机名或FQDN访问主机,并且我不想依赖证书来拥有所有这些有效字段)
根据官方文档,我可以使用自定义开启工具HTTPSHandler
来禁用主机名检查(https://docs.python.org/3/library/urllib.request.html)
但是,由于Python Issue18543(http://bugs.python.org/issue18543),如果指定了任何ca *参数,urllib.request.urlopen()
将忽略已安装的opener。
我的问题是:
解决此问题的最佳方法是什么?我应该尝试覆盖urllib.request.urlopen()
方法吗?如果是这样,这是如何以pythonic方式完成的?
还有其他选择吗?我真的不想重写和维护很多基本代码。
到目前为止我的代码(不工作)如下:
import ssl
import urllib.request # used to be import urllib2 in python 2.x
#create an HTTPS Handler that does not check the hostname
https_handler = urllib.request.HTTPSHandler(debuglevel=0, check_hostname=False)
opener = urllib.request.build_opener(https_handler)
urllib.request.install_opener(opener)
# PROBLEM is that this opener will not be used by urlopen.
# solution: override the urlopen method?
# verify server certificate
try:
urllib.request.urlopen("https://127.0.0.1:4443", cafile="cert.pem")
except ssl.CertificateError as e:
print ("Certificate Error:",e)
return -1
return 0
运行代码会出现有关主机名不匹配的证书错误。
此问题也在这里讨论过: http://www.gossamer-threads.com/lists/python/bugs/1005966?do=post_view_threaded
特别是这篇文章提出了一个解决方法: http://www.gossamer-threads.com/lists/python/bugs/1006048?do=post_view_threaded#1006048
答案 0 :(得分:0)
这似乎不是一项微不足道的任务,从长远来看大多数解决方案都不可靠。
我想发布我选择解决此问题的解决方案。
首先,我选择使用urllib3库(https://pypi.python.org/pypi/urllib3)。
从文档中,我发现最容易使用PoolManager:
import urllib3
http = urllib3.PoolManager(cert_reqs='CERT_REQUIRED',
ca_certs="cert.pem",
assert_hostname=False)
try:
r = http.request('GET', 'https://127.0.0.1:4443/')
print("STATUS:", r.status)
print("Certificate verification NO HOSTNAME successful")
except urllib3.exceptions.SSLError as e:
print ("SSL Error:", e)
return -1
return 0
请注意,在urllib3 verison 1.10中忽略assert_hostname = False: https://github.com/shazow/urllib3/issues/524