我收到以下错误:
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。我怎样才能让它绕过验证?
这不是针对您的特定问题的解决方案,但我将其放在这里是因为该线程是“SSL:CERTIFICATE_VERIFY_FAILED”的最高 Google 结果,它使我大吃一惊。
如果您在 OSX 上安装了 Python 3.6 并在尝试连接到 https:// 站点时收到“SSL:CERTIFICATE_VERIFY_FAILED”错误,这可能是因为 OSX 上的 Python 3.6 根本没有证书,并且无法验证任何 SSL连接。这是对 OSX 上 3.6 的更改,需要安装后步骤,即安装 certifi
证书包。这记录在文件 ReadMe.rtf 中,您可以在 /Applications/Python\ 3.6/ReadMe.rtf
中找到该文件(另请参阅文件 Conclusion.rtf 和生成 macOS 安装程序的脚本 build-installer.py
)。
自述文件将让您在 /Applications/Python\ 3.6/Install\ Certificates.command
(其源为 install_certificates.command
)处运行安装后脚本,其中:
首先安装 Python 包 certifi,然后
然后创建从 OpenSSL 证书文件到包 certifi 安装的证书文件的符号链接。
发行说明有更多信息:https://www.python.org/downloads/release/python-360/
在较新版本的 Python 上,有更多关于此的文档:
https://github.com/python/cpython/blob/e05a703848473b0365886dcc593cbddc46609f29/Mac/BuildScript/resources/ReadMe.rtf#L22-L34
https://github.com/python/cpython/blob/e05a703848473b0365886dcc593cbddc46609f29/Mac/BuildScript/resources/Conclusion.rtf#L15-L19
https://github.com/python/cpython/blob/e05a703848473b0365886dcc593cbddc46609f29/Mac/BuildScript/resources/Welcome.rtf#L23-L25
https://github.com/python/cpython/blob/e05a703848473b0365886dcc593cbddc46609f29/Mac/BuildScript/resources/install_certificates.command
https://github.com/python/cpython/blob/e05a703848473b0365886dcc593cbddc46609f29/Mac/BuildScript/README.rst
https://github.com/python/cpython/blob/e05a703848473b0365886dcc593cbddc46609f29/Mac/BuildScript/build-installer.py#L239-L246
如果您只是想绕过验证,可以创建一个新的 SSLContext。默认情况下,新创建的上下文使用 CERT_NONE。
如第 17.3.7.2.1 节所述,请注意这一点
直接调用 SSLContext 构造函数时,CERT_NONE 是默认值。由于它不对其他对等方进行身份验证,因此它可能是不安全的,尤其是在客户端模式下,在大多数情况下您希望确保正在与之交谈的服务器的真实性。因此,在客户端模式下,强烈建议使用 CERT_REQUIRED。
但是,如果您只是出于其他原因希望它现在可以工作,您可以执行以下操作,您还必须import 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 中所述:
本指南主要针对希望采用较新版本的 Python 以在尚不支持 HTTPS 连接上的证书验证的旧环境中实现此 PEP 的系统管理员。例如,管理员可以通过将上面的 monkeypatch 添加到他们的 Python 标准操作环境中的 sitecustomize.py 来选择退出。应用程序和库不应该在整个过程中进行这种更改(除非可能是为了响应系统管理员控制的配置设置)。
如果您想阅读一篇关于为什么不验证证书在软件中不好的论文 you can find it here!
setup.py upload
,我该如何解决?
certifi
并更新盒子上的 openssl。
context
是我需要的
扩展 Craig Glennie 的回答:
在 MacOs Sierra 上的 Python 3.6.1 中
在 bash 终端中输入这个可以解决问题:
pip install certifi
/Applications/Python\ 3.6/Install\ Certificates.command
sudo /Applications/Python\ 3.6/Install\ Certificates.command
。
在 Windows 上,Python 不查看系统证书,它使用位于 ?\lib\site-packages\certifi\cacert.pem
的自己的证书。
您的问题的解决方案:
将域验证证书下载为 *.crt 或 *pem 文件在编辑器中打开文件并将其内容复制到剪贴板找到您的 cacert.pem 位置: from requests.utils import DEFAULT_CA_BUNDLE_PATH; print(DEFAULT_CA_BUNDLE_PATH) 编辑 cacert.pem 文件并将您的域验证证书粘贴到文件末尾。保存文件并享受请求!
lib\site-packages\certifi\cacert.pem
在 Python 2.7.10 中不存在。问题是关于 urllib2
而不是 requests
/usr/local/lib/python2.7/dist-packages/certifi-2015.09.06.2-py2.7.egg/certifi/cacert.pem
。谢谢!
尽管我在 Python 3.4、3.5 和 3.6 中使用了 urllib.request.urlopen
,但我遇到了类似的问题。 (这是 Python 3 中 urllib2
的一部分,根据 Python 2 的 urllib2
documentation page 开头的注释。)
我的解决方案是 pip install certifi
安装 certifi
,它具有:
... 精心策划的根证书集合,用于验证 SSL 证书的可信度,同时验证 TLS 主机的身份。
然后,在我之前刚刚拥有的代码中:
import urllib.request as urlrq
resp = urlrq.urlopen('https://example.com/bar/baz.html')
我将其修改为:
import urllib.request as urlrq
import certifi
resp = urlrq.urlopen('https://example.com/bar/baz.html', cafile=certifi.where())
如果我正确阅读了 urllib2.urlopen
documentation,它还有一个 cafile
参数。因此,urllib2.urlopen([...], certifi.where())
也可能适用于 Python 2.7。
更新 (2020-01-01): 从 Python 3.6 开始,the cafile
argument to urlopen
has been deprecated,应该指定 context
参数。我发现以下在 3.5 到 3.8 上同样适用:
import urllib.request as urlrq
import certifi
import ssl
resp = urlrq.urlopen('https://example.com/bar/baz.html', context=ssl.create_default_context(cafile=certifi.where()))
load_verify_locations
改变 SSLContext
实例并返回 None
。您应该改用 context=ssl.create_default_context(cafile=certifi.where())
。有关详细信息,请参阅 ssl
docs。
ssl
函数。见编辑;好?
https://.../baz.html
只是一个假网站地址,用于演示语法。 2) 导入需要进入调用 urlopen()
(或任何资源打开器)函数的任何模块,并且指向 certifi
证书的新 SSL 上下文需要作为 context
关键字传递到打开器争论)。
我的 Mac OS X 解决方案:
1) 使用从官方 Python 语言网站下载的本机应用 Python 安装程序升级到 Python 3.6.5 https://www.python.org/downloads/
我发现这个安装程序在更新新 Python 的链接和符号链接方面比自制软件要好得多。
2) 使用刷新的 Python 3.6 目录中的“./Install Certificates.command”安装新证书
> cd "/Applications/Python 3.6/"
> sudo "./Install Certificates.command"
您可以尝试将其添加到您的环境变量中:
PYTHONHTTPSVERIFY=0
请注意,这将禁用所有 HTTPS 验证,因此有点像大锤方法,但是如果不需要验证,它可能是一个有效的解决方案。
我在我的一台 Linux 机器上遇到了类似的问题。生成新证书并导出指向证书目录的环境变量为我修复了它:
$ sudo update-ca-certificates --fresh
$ export SSL_CERT_DIR=/etc/ssl/certs
import requests
requests.packages.urllib3.disable_warnings()
import ssl
try:
_create_unverified_https_context = ssl._create_unverified_context
except AttributeError:
# Legacy Python that doesn't verify HTTPS certificates by default
pass
else:
# Handle target environment that doesn't support HTTPS verification
ssl._create_default_https_context = _create_unverified_https_context
取自这里https://gist.github.com/michaelrice/a6794a017e349fc65d01
就像我在评论中写的那样,这个问题可能与 this SO answer 有关。
简而言之:有多种方法可以验证证书。 OpenSSL 使用的验证与您系统上的受信任根证书不兼容。 Python 使用 OpenSSL。
您可以尝试获取 Verisign Class 3 Public Primary Certification Authority 的缺失证书,然后根据 Python documentation 使用 cafile
选项:
urllib2.urlopen(req, cafile="verisign.pem")
$ cd $HOME
$ wget --quiet https://curl.haxx.se/ca/cacert.pem
$ export SSL_CERT_FILE=$HOME/cacert.pem
来源:https://access.redhat.com/articles/2039753
Anaconda 的解决方案
我的设置是 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.datasets
和类似的工具应该可以工作。
进一步的注意事项
其他解决方案不起作用,因为 Anaconda 设置略有不同:
路径 Applications/Python\ 3.X 根本不存在。
以下命令提供的路径是错误的路径
from requests.utils import DEFAULT_CA_BUNDLE_PATH
DEFAULT_CA_BUNDLE_PATH
我需要添加另一个答案,因为就像 Craig Glennie 一样,由于网络上很多帖子都提到了这个问题,我进行了一次疯狂的追逐。
我正在使用 MacPorts,我最初认为是 Python 问题实际上是 MacPorts 问题:它不会在安装 openssl 时安装根证书。解决方案是 port install curl-ca-bundle
,如 this blog post 中所述。
我很惊讶所有这些指令都没有解决我的问题。尽管如此,诊断结果是正确的(顺便说一句,我使用的是 Mac 和 Python3.6.1)。因此,总结正确的部分:
在 Mac 上,Apple 正在放弃 OpenSSL
Python 现在使用它自己的一组 CA 根证书
二进制 Python 安装提供了一个脚本来安装 Python 需要的 CA Root 证书(“/Applications/Python 3.6/Install Certificates.command”)
阅读“/Applications/Python 3.6/ReadMe.rtf”了解详情
对我来说,脚本不起作用,所有那些 certifi 和 openssl 安装也无法修复。也许是因为我有多个 python 2 和 3 安装,以及许多 virtualenv。最后,我需要手动修复它。
pip install certifi # for your virtualenv
mkdir -p /Library/Frameworks/Python.framework/Versions/3.6/etc/openssl
cp -a <your virtualenv>/site-package/certifi/cacert.pem \
/Library/Frameworks/Python.framework/Versions/3.6/etc/openssl/cert.pem
如果这仍然让你失败。然后重新/安装 OpenSSL。
port install openssl
我在 here 上找到了这个
我找到了这个解决方案,在源文件的开头插入这段代码:
import ssl
try:
_create_unverified_https_context = ssl._create_unverified_context
except AttributeError:
# Legacy Python that doesn't verify HTTPS certificates by default
pass
else:
# Handle target environment that doesn't support HTTPS verification
ssl._create_default_https_context = _create_unverified_https_context
此代码使验证撤消,因此不验证 ssl 认证。
Python 2.7.12(默认,2016 年 7 月 29 日,15:26:22)修复了上述问题。此信息可能对其他人有所帮助。
SSL: CERTIFICATE_VERIFY_FAILED 错误也可能发生,因为 Linux 上的 ca-certificates
包中缺少中间证书。例如,在我的例子中,中间证书“DigiCert SHA2 Secure Server CA”在 ca-certificates
包中丢失,即使 Firefox 浏览器包含它。您可以通过直接在导致此错误的 URL 上运行 wget
命令来找出缺少哪个证书。然后,您可以从证书颁发机构的官方网站(例如,在我的例子中为 https://www.digicert.com/digicert-root-certificates.htm)搜索此证书的 CRT 文件的相应链接。现在,要包含您的案例中缺少的证书,您可以使用您的 CRT 文件下载链接运行以下命令:
wget https://cacerts.digicert.com/DigiCertSHA2SecureServerCA.crt
mv DigiCertSHA2SecureServerCA.crt DigiCertSHA2SecureServerCA.der
openssl x509 -inform DER -outform PEM -in DigiCertSHA2SecureServerCA.der -out DigicertSHA2SecureServerCA.pem.crt
sudo mkdir /usr/share/ca-certificates/extra
sudo cp DigicertSHA2SecureServerCA.pem.crt /usr/share/ca-certificates/extra/
sudo dpkg-reconfigure ca-certificates
在此之后,您可以使用 wget
再次测试您的 URL 以及使用 python urllib
包。有关详细信息,请参阅:https://bugs.launchpad.net/ubuntu/+source/ca-certificates/+bug/1795242
看一眼
/Applications/Python 3.6/Install Certificates.command
您也可以前往 Finder 中的 Applications
文件夹并点击 Certificates.command
对于 Centos 6/7、Fedora 上的 Python 3.4+,只需以这种方式安装受信任的 CA:
将 CA.crt 复制到 /etc/pki/ca-trust/source/anchors/update-ca-trust force-enable update-ca-trust extract
像你一样,我在我的旧 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
中名为 Certificate verification and OpenSSL [CHANGED for Python 2.7.9]
的一章详细解释了这个问题。
因此,请检查、下载并在您的 PATH 中放入正确版本的 python。
我半羞愧地低下了头,因为我遇到了同样的问题,除了在我的情况下,我点击的 URL 是有效的,证书是有效的。无效的是我与网络的连接。我未能将代理详细信息添加到浏览器(本例中为 IE)。这阻止了验证过程的正确进行。添加了代理详细信息,然后我的 python 非常高兴。
带有 centOS 7 的 Amazon EC2 上的 Python 2.7
我必须将环境变量 SSL_CERT_DIR
设置为指向位于 /etc/ssl/certs/ca-bundle.crt
的 ca-bundle
SSL_CERT_DIR
设置为 /etc/ssl/certs
,并确保 ca-certificates
软件包已安装并且是最新的。
export SSL_CERT_FILE=/etc/ssl/certs/ca-bundle.crt
。正如查理伯恩斯所指出的,这个问题已经在access.redhat.com/articles/2039753中详细讨论过
在某些情况下,您不能使用不安全的连接或将 ssl 上下文传递给 urllib 请求。这是我基于 https://stackoverflow.com/a/28052583/6709778 的解决方案
如果您想使用自己的证书文件
import ssl
def new_ssl_context_decorator(*args, **kwargs):
kwargs['cafile'] = '/etc/ssl/certs/ca-certificates.crt'
return ssl.create_default_context(*args, **kwargs)
ssl._create_default_https_context = ssl._create_unverified_context
或者您可以使用证书中的共享文件
def new_ssl_context_decorator(*args, **kwargs):
import certifi
kwargs['cafile'] = certifi.where()
return ssl.create_default_context(*args, **kwargs)
使用 pip
安装 PyOpenSSL
对我有用(无需转换为 PEM):
pip install PyOpenSSL
我通过关闭 Fiddler(一个 HTTP 调试代理)解决了这个问题,检查您是否启用了代理,然后重试。
在 python 2.7 中,在文件 C:\Python27\lib\site-packages\certifi\cacert.pem 的末尾添加受信任的根 CA 详细信息有帮助
之后我确实运行(使用管理员权限) pip install --trusted-host pypi.python.org --trusted-host pypi.org --trusted-host files.pythonhosted.org packageName
在 Mac 上安装证书解决了我的问题:
pip install certifi
就我而言,我收到此错误是因为 requests
和 urllib3
版本不兼容,在安装过程中出现以下错误:
ERROR: requests 2.21.0 has requirement urllib3<1.25,>=1.21.1, but you'll have urllib3 1.25 which is incompatible.
pip install 'urllib3<1.25' --force-reinstall
成功了。
另一个 Anaconda 解决方案。我在 macOS 上的 Python 2.7 环境中获得了 CERTIFICATE_VERIFY_FAILED。事实证明 conda 路径很糟糕:
基础(3.7)环境:
>>> import ssl
>>> ssl.get_default_verify_paths()
DefaultVerifyPaths(cafile='/usr/local/anaconda3/ssl/cert.pem', capath=None, openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/usr/local/anaconda3/ssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/usr/local/anaconda3/ssl/certs')
2.7 环境(路径不存在!):
DefaultVerifyPaths(cafile='', capath=None, openssl_cafile_env='SSL_CERT_FILE', openssl_cafile='/usr/local/anaconda3/envs/py27/ssl/cert.pem', openssl_capath_env='SSL_CERT_DIR', openssl_capath='/usr/local/anaconda3/envs/py27/ssl/certs')
修复:
cd /usr/local/anaconda3/envs/py27/
mkdir ssl
cd ssl
ln -s ../../../ssl/cert.pem
我遇到了同样的错误,并且在我放弃并开始自己尝试之前也进行了很长一段时间的疯狂追逐。我最终想通了,所以我想我会分享。就我而言,我在 Linux 上运行 Python 2.7.10(由于我无法控制的原因),无权访问请求模块,无法在操作系统或 Python 级别全局安装证书,无法设置任何环境变量,并且需要访问使用内部颁发的证书的特定内部站点。
注意:禁用 SSL 验证从来都不是一个选项。我正在下载一个立即以 root 身份运行的脚本。如果没有 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()
像魅力一样工作,并且不会影响安全性。
享受!
/Applications/Python\ 3.7/Install\ Certificates.command
,直接在terminal
中运行它!谢谢@CraigGlennie & @muyong 我感谢out-of-the-box-thinking
把它放在这里!