使用urllib.request验证HTTPS证书
我正在尝试使用Python 3的urlopen
方法打开一个https网址,这个方法在urllib.request
模块里。看起来这个方法可以正常工作,但文档上提醒说:“如果既没有指定cafile
也没有指定capath
,那么HTTPS请求将不会验证服务器的证书。”
我猜如果我不想让我的程序受到中间人攻击、证书被撤销的问题以及其他安全隐患的影响,我需要指定其中一个参数。
cafile
和capath
应该指向一个证书列表。我应该从哪里获取这个列表呢?有没有简单且跨平台的方法,可以使用我操作系统或浏览器所用的相同证书列表?
7 个回答
在编程中,有时候我们会遇到一些问题,比如代码运行不正常或者出现错误。这些问题可能是因为我们没有正确理解某些概念,或者在写代码时犯了一些小错误。
当你在网上寻找解决方案时,像StackOverflow这样的社区非常有帮助。在这里,很多有经验的程序员会分享他们的知识和经验,帮助你解决问题。
如果你看到一些代码块,比如
import certifi
import ssl
import urllib.request
try:
from urllib.request import HTTPSHandler
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
context.options |= ssl.OP_NO_SSLv2
context.verify_mode = ssl.CERT_REQUIRED
context.load_verify_locations(certifi.where(), None)
https_handler = HTTPSHandler(context=context, check_hostname=True)
opener = urllib.request.build_opener(https_handler)
except ImportError:
opener = urllib.request.build_opener()
opener.addheaders = [('User-agent', YOUR_USER_AGENT)]
urllib.request.install_opener(opener)
,这些通常是用来展示具体的代码示例,帮助你更好地理解如何解决问题。
总之,遇到问题时,不要气馁,利用好这些资源,慢慢学习和积累经验,你会越来越熟练的。
你可以在 http://curl.haxx.se/docs/caextract.html 下载Mozilla的证书,这些证书是可以用在urllib里的,格式是PEM格式。
Elias Zamarias 的回答仍然有效,但会出现一个过时的警告:
DeprecationWarning: cafile, cpath and cadefault are deprecated, use a custom context instead.
我用另一种方法解决了同样的问题(使用 Python 3.7.0):
import ssl
import urllib.request
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
response = urllib.request.urlopen("http://www.example.com", context=ssl_context)
在Python 2.7及以上版本中可以使用
context = ssl.create_default_context(cafile=certifi.where())
req = urllib2.urlopen(urllib2.Request(url, body, headers), context=context)
我找到一个可以帮我完成目标的库:Certifi。你可以通过在命令行中运行 pip install certifi
来安装它。
现在,发送请求和验证请求变得简单了:
import certifi
import urllib.request
urllib.request.urlopen("https://example.com/", cafile=certifi.where())
正如我预期的那样,对于一个有有效证书的网站,它会返回一个 HTTPResponse
对象;而对于一个证书无效的网站,它会抛出一个 ssl.CertificateError
异常。