使用urllib.request验证HTTPS证书

10 投票
7 回答
20718 浏览
提问于 2025-04-18 10:49

我正在尝试使用Python 3的urlopen方法打开一个https网址,这个方法在urllib.request模块里。看起来这个方法可以正常工作,但文档上提醒说:“如果既没有指定cafile也没有指定capath,那么HTTPS请求将不会验证服务器的证书。”

我猜如果我不想让我的程序受到中间人攻击、证书被撤销的问题以及其他安全隐患的影响,我需要指定其中一个参数。

cafilecapath应该指向一个证书列表。我应该从哪里获取这个列表呢?有没有简单且跨平台的方法,可以使用我操作系统或浏览器所用的相同证书列表?

7 个回答

2

在编程中,有时候我们会遇到一些问题,比如代码运行不正常或者出现错误。这些问题可能是因为我们没有正确理解某些概念,或者在写代码时犯了一些小错误。

当你在网上寻找解决方案时,像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)
,这些通常是用来展示具体的代码示例,帮助你更好地理解如何解决问题。

总之,遇到问题时,不要气馁,利用好这些资源,慢慢学习和积累经验,你会越来越熟练的。

2

你可以在 http://curl.haxx.se/docs/caextract.html 下载Mozilla的证书,这些证书是可以用在urllib里的,格式是PEM格式。

5

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)
12

在Python 2.7及以上版本中可以使用

context = ssl.create_default_context(cafile=certifi.where())
req = urllib2.urlopen(urllib2.Request(url, body, headers), context=context)
8

我找到一个可以帮我完成目标的库:Certifi。你可以通过在命令行中运行 pip install certifi 来安装它。

现在,发送请求和验证请求变得简单了:

import certifi
import urllib.request

urllib.request.urlopen("https://example.com/", cafile=certifi.where())

正如我预期的那样,对于一个有有效证书的网站,它会返回一个 HTTPResponse 对象;而对于一个证书无效的网站,它会抛出一个 ssl.CertificateError 异常。

撰写回答