我得到以下错误:

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。我怎样才能让它绕过验证呢?


当前回答

像你一样,我在我的旧iMac (OS X 10.6.8)上使用python 2.7,我也遇到了这个问题,使用urllib2。urlopen:

urlopen error [SSL: CERTIFICATE_VERIFY_FAILED]

我的程序运行得很好,没有SSL证书问题,突然(在下载程序后),它们因SSL错误而崩溃。

问题是使用的python版本:

https://www.python.org/downloads和python-2.7.9-macosx10.6.pkg没有问题 Homebrew工具安装的“brew install python”有问题,版本位于/usr/local/bin。

在/Applications/Python 2.7/ReadMe.rtf中,有一章名为证书验证和OpenSSL[已更改为Python 2.7.9],详细解释了这个问题。

因此,检查,下载并将正确版本的python放入您的PATH中。

其他回答

如果只想绕过验证,可以创建一个新的SSLContext。默认情况下,新创建的上下文使用CERT_NONE。

如17.3.7.2.1节所述,请注意这一点

当直接调用SSLContext构造函数时,CERT_NONE是默认值。由于它不验证另一个对等体,因此它可能是不安全的,特别是在客户端模式下,大多数时候您希望确保与之通信的服务器的真实性。因此,在客户端模式下,强烈建议使用CERT_REQUIRED。

但如果你只是想让它现在工作,你可以做以下事情,你也必须导入ssl:

input = input.replace("!web ", "")      
url = "https://domainsearch.p.mashape.com/index.php?name=" + input
req = urllib2.Request(url, headers={ 'X-Mashape-Key': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' })
gcontext = ssl.SSLContext()  # Only for gangstars
info = urllib2.urlopen(req, context=gcontext).read()
Message.Chat.SendMessage ("" + info)

这应该可以解决您的问题,但您并没有真正解决任何问题,但您不会看到[SSL: CERTIFICATE_VERIFY_FAILED],因为您现在没有验证证书!

为了补充以上内容,如果您想了解更多关于为什么会遇到这些问题的信息,请参阅PEP 476。

这个PEP建议在默认情况下启用X509证书签名的验证,以及Python的HTTP客户端的主机名验证,并在每次调用的基础上选择退出。此更改将应用于Python 2.7、Python 3.4和Python 3.5。

有一个建议选择退出,这与我上面的建议没有什么不同:

import ssl

# This restores the same behavior as before.
context = ssl._create_unverified_context()
urllib.urlopen("https://no-valid-cert", context=context)

它还提供了一个非常不推荐的monkeypatching选项,这在python中并不常见:

import ssl

ssl._create_default_https_context = ssl._create_unverified_context

它用创建未经验证的上下文的函数覆盖用于创建上下文的默认函数。

请注意PEP中所述:

This guidance is aimed primarily at system administrators that wish to adopt newer versions of Python that implement this PEP in legacy environments that do not yet support certificate verification on HTTPS connections. For example, an administrator may opt out by adding the monkeypatch above to sitecustomize.py in their Standard Operating Environment for Python. Applications and libraries SHOULD NOT be making this change process wide (except perhaps in response to a system administrator controlled configuration setting).

如果你想读一篇关于为什么不验证证书是不好的软件的论文,你可以在这里找到它!

就像我在评论中写的,这个问题可能与这个SO答案有关。

简而言之:有多种方法来验证证书。OpenSSL使用的验证与系统上的受信任根证书不兼容。OpenSSL是Python使用的。

您可以尝试获取Verisign Class 3 Public Primary Certification Authority缺少的证书,然后根据Python文档使用cafile选项:

urllib2.urlopen(req, cafile="verisign.pem")

这里已经有很多答案了,但我们在一个非常具体的案例中遇到了这个问题,花了很多时间调查,所以再加一个。我们在下面的例子中看到:

在一个德比安式细长的码头集装箱里 默认Python 3.5.3 easy_install3 对于在Kubernetes集群中使用cert-manager注册的LetsEncrypt证书

pip3和openssl命令行都能够验证该证书,easy_install3能够成功验证其他LetsEncrypt证书。

解决办法是从源代码构建最新的Python(当时是3.7.3)。这里的说明很详细,很容易理解。

我认为你有几种方法可以解决这个问题。我提到了以下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"

水蟒的解决方案

我的设置是带有代理的MacOS上的Anaconda Python 3.7。路径不同。

这是如何获得正确的证书路径:

import ssl
ssl.get_default_verify_paths()

我的系统产生了什么

Out[35]: DefaultVerifyPaths(cafile='/miniconda3/ssl/cert.pem', capath=None,
 openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/miniconda3/ssl/cert.pem',
 openssl_capath_env='SSL_CERT_DIR', openssl_capath='/miniconda3/ssl/certs')

一旦知道了证书的位置,就可以将代理使用的证书连接到该文件的末尾。

我已经设置了conda与我的代理工作,通过运行:

conda config --set ssl_verify <pathToYourFile>.crt

如果你不记得你的证书在哪里,你可以在~/.condarc中找到它:

ssl_verify: <pathToYourFile>.crt

现在将该文件连接到/miniconda3/ssl/cert.pem文件的末尾 请求应该起作用,尤其是sklearn。数据集和类似的工具 应该工作。

进一步的说明

其他解决方案没有工作,因为Anaconda设置略有不同:

路径为Applications/Python\ 3。X根本不存在。 下面命令提供的路径是错误的路径

from requests.utils import DEFAULT_CA_BUNDLE_PATH
DEFAULT_CA_BUNDLE_PATH