使用 urllib.request 验证 HTTPS 证书

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

我正在尝试使用 Python 3 的

urlopen
模块中的
urllib.request
方法打开 https URL。它似乎工作正常,但文档警告“如果既没有指定
cafile
也没有指定
capath
,则 HTTPS 请求不会对服务器的证书进行任何验证”。

我猜如果我不希望我的程序容易受到中间人攻击、吊销证书问题和其他漏洞,我需要指定这些参数之一。

cafile
capath
应该指向证书列表。我应该从哪里得到这个清单?是否有任何简单且跨平台的方法来使用我的操作系统或浏览器使用的相同证书列表?

python ssl python-3.x https urllib
6个回答
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
异常。


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)

2
投票

您可以在 http://curl.haxx.se/docs/caextract.html

下载可用于 urllib 的格式的 Mozilla 证书(例如 PEM 格式)

2
投票
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)

1
投票

不同的 Linux 发行版有不同的包名称。我在 Centos 和 Ubuntu 上进行了测试。这些证书包是随系统更新而更新的。因此,您可以检测哪个捆绑包可用并将其与

urlopen
一起使用。

import os
cafile = None
for i in [
    '/etc/ssl/certs/ca-bundle.crt',
    '/etc/ssl/certs/ca-certificates.crt',
]:
    if os.path.exists(i):
        cafile = i
        break
if cafile is None:
    raise RuntimeError('System CA-certificates bundle not found')
© www.soinside.com 2019 - 2024. All rights reserved.