我得到以下错误:
Exception in thread Thread-3:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 810, in __bootstrap_inner
self.run()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 763, in run
self.__target(*self.__args, **self.__kwargs)
File "/Users/Matthew/Desktop/Skypebot 2.0/bot.py", line 271, in process
info = urllib2.urlopen(req).read()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 154, in urlopen
return opener.open(url, data, timeout)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 431, in open
response = self._open(req, data)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 449, in _open
'_open', req)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 409, in _call_chain
result = func(*args)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 1240, in https_open
context=self._context)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 1197, in do_open
raise URLError(err)
URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:581)>
下面是导致这个错误的代码:
if input.startswith("!web"):
input = input.replace("!web ", "")
url = "https://domainsearch.p.mashape.com/index.php?name=" + input
req = urllib2.Request(url, headers={ 'X-Mashape-Key': 'XXXXXXXXXXXXXXXXXXXX' })
info = urllib2.urlopen(req).read()
Message.Chat.SendMessage ("" + info)
我正在使用的API要求我使用HTTPS。我怎样才能让它绕过验证呢?
I was getting the same error, and also went on a wild goose chase for quite a while before I gave up and started trying things on my own. I eventually figured it out, so I thought I'd share. In my case, I am running Python 2.7.10 (due to reasons beyond my control) on Linux, don't have access to the requests module, can't install certificates globally at the OS or Python level, can't set any environment variables, and need to access a specific internal site that uses internally issued certificates.
注意:禁用SSL验证从来不是一个选项。我正在下载一个脚本,它可以立即以根用户的身份运行。没有SSL验证,任何web服务器都可以假装是我的目标主机,而我只是接受他们给我的任何东西,并以root身份运行它!
我将根证书和中间证书(可能不止一个)以pem格式保存到一个文件中,然后使用以下代码:
import ssl,urllib2
data = urllib2.build_opener(urllib2.HTTPSHandler(context=ssl.create_default_context(cafile='/path/to/ca-cert-chain.pem')), urllib2.ProxyHandler({})).open('https://your-site.com/somefile').read()
print(data)
注意,我在那里添加了urllib2.ProxyHandler({})。这是因为在我们的环境中,代理是默认设置的,但它们只能访问外部站点,不能访问内部站点。如果没有代理绕过,我就无法访问内部站点。如果你没有这个问题,你可以简化如下:
data = urllib2.build_opener(urllib2.HTTPSHandler(context=ssl.create_default_context(cafile='/path/to/ca-cert-chain.pem'))).open('https://your-site.com/somefile').read()
工作起来很有魅力,而且不会危及安全。
享受吧!
我认为你有几种方法可以解决这个问题。我提到了以下5种方法:
你可以为每个请求定义上下文,并在每个请求上传递上下文,如下所示:
import certifi
import ssl
import urllib
context = ssl.create_default_context(cafile=certifi.where())
result = urllib.request.urlopen('https://www.example.com', context=context)
或在环境中设置证书文件。
import os
import certifi
import urllib
os.environ["REQUESTS_CA_BUNDLE"] = certifi.where()
os.environ["SSL_CERT_FILE"] = certifi.where()
result = urllib.request.urlopen('https://www.example.com')
创建默认的https上下文方法:
import certifi
import ssl
ssl._create_default_https_context = lambda: ssl.create_default_context(cafile=certifi.where())
result = urllib.request.urlopen('https://www.example.com')
如果您使用Linux机器,生成新的证书并导出指向证书目录的环境变量,则可以修复该问题。
$ sudo update-ca-certificates --fresh
$ export SSL_CERT_DIR=/etc/ssl/certs
或如果您使用Mac机器,生成新的证书
$ cd "/Applications/$(python3 --version | awk '{print $2}'| awk -F. '{print "Python " $1"."$2}')"
$ sudo "./Install Certificates.command"