我正在尝试使用Python 3的urlopen
模块中的urllib.request
方法打开https网址。它似乎工作正常,但文档警告说,{#1}}和cafile
都没有指定,HTTPS请求不会对服务器的证书进行任何验证"。
我猜我需要指定其中一个参数,如果我不希望我的程序容易受到中间人攻击,撤销证书问题和其他漏洞的攻击。</ p>
capath
和cafile
应该指向证书列表。我应该从哪里获得此列表?是否有任何简单和跨平台的方法来使用我的操作系统或浏览器使用的相同证书列表?
答案 0 :(得分:2)
我找到了一个可以做我想做的事情的图书馆:Certifi。可以通过从命令行运行pip install certifi
来安装它。
现在可以轻松地发出请求并进行验证:
import certifi
import urllib.request
urllib.request.urlopen("https://example.com/", cafile=certifi.where())
正如我所料,这会为具有有效证书的网站返回HTTPResponse
对象,并为证书无效的网站引发ssl.CertificateError
例外。
答案 1 :(得分:1)
答案 2 :(得分:1)
不同的Linux发行版具有不同的包名称。我在Centos和Ubuntu中测试过。这些证书包是系统更新的更新。因此,您可能只是检测哪个捆绑包可用,并将其与urlopen
一起使用。
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')
答案 3 :(得分:1)
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)
答案 4 :(得分:0)
在python 2.7及更高版本中工作
context = ssl.create_default_context(cafile=certifi.where())
req = urllib2.urlopen(urllib2.Request(url, body, headers), context=context)
答案 5 :(得分:0)
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)