Python urllib 和“SSL:CERTIFICATE_VERIFY_FAILED”错误

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27835619/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 02:20:39  来源:igfitidea点击:

urllib and "SSL: CERTIFICATE_VERIFY_FAILED" Error

pythonpython-2.7sslssl-certificateurllib

提问by user3724476

I am getting the following error:

我收到以下错误:

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)>

This is the code that is causing this error:

这是导致此错误的代码:

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)

The API I'm using requires me to use HTTPS. How can I make it bypass the verification?

我使用的 API 要求我使用 HTTPS。我怎样才能让它绕过验证?

采纳答案by Noelkd

If you justwant to bypass verification, you can create a new SSLContext. By default newly created contexts use CERT_NONE.

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

Be careful with this as stated in section 17.3.7.2.1

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

When calling the SSLContext constructor directly, CERT_NONE is the default. Since it does not authenticate the other peer, it can be insecure, especially in client mode where most of time you would like to ensure the authenticity of the server you're talking to. Therefore, when in client mode, it is highly recommended to use CERT_REQUIRED.

直接调用 SSLContext 构造函数时,CERT_NONE 是默认值。由于它不对其他对等点进行身份验证,因此它可能不安全,尤其是在客户端模式下,大多数时候您都希望确保与之交谈的服务器的真实性。因此,在客户端模式下,强烈建议使用 CERT_REQUIRED。

But if you just want it to work now for some other reason you can do the following, you'll have to import sslas well:

但是,如果您只是出于其他原因希望它现在可以工作,则可以执行以下操作,您也必须这样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)

This should get round your problem but you're not really solving any of the issues, but you won't see the [SSL: CERTIFICATE_VERIFY_FAILED]because you now aren't verifying the cert!

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

To add to the above, if you want to know more about why you are seeing these issues you will want to have a look at PEP 476.

要补充上述内容,如果您想更多地了解为什么会看到这些问题,您需要查看PEP 476

This PEP proposes to enable verification of X509 certificate signatures, as well as hostname verification for Python's HTTP clients by default, subject to opt-out on a per-call basis. This change would be applied to Python 2.7, Python 3.4, and Python 3.5.

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

There is an advised opt out which isn't dissimilar to my advice above:

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

import ssl

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

It also features a highly discouragedoption via monkeypatchingwhich you don't often see in python:

它还通过monkeypatching提供了一个非常不鼓励的选项,这在python 中并不常见:

import ssl

ssl._create_default_https_context = ssl._create_unverified_context

Which overrides the default function for context creation with the function to create an unverified context.

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

Please note with this as stated in the PEP:

请注意 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).

本指南主要针对希望采用较新版本 Python 的系统管理员,这些 Python 版本在尚不支持 HTTPS 连接上的证书验证的旧环境中实现此 PEP。例如,管理员可以通过将上面的monkeypatch 添加到他们的Python 标准操作环境中的sitecustomize.py 来选择退出。应用程序和库不应该在整个更改过程中进行(除非可能响应系统管理员控制的配置设置)。

If you want to read a paper on why not validating certs is bad in software you can find it here!

如果您想阅读有关为什么不在软件中验证证书不好的论文,您可以在这里找到它

回答by Steffen Ullrich

Like I've written in a comment, this problem is probably related to this SO answer.

就像我在评论中写的那样,这个问题可能与这个 SO answer 有关

In short: there are multiple ways to verify the certificate. The verification used by OpenSSL is incompatible with the trusted root certificates you have on your system. OpenSSL is used by Python.

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

You could try to get the missing certificate for Verisign Class 3 Public Primary Certification Authorityand then use the cafileoption according to the Python documentation:

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

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

回答by Thierry Maillard

Like you, I am using python 2.7 on my old iMac (OS X 10.6.8), I met the problem too, using urllib2.urlopen :

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

urlopen error [SSL: CERTIFICATE_VERIFY_FAILED]

My programs were running fine without SSL certificate problems and suddently (after dowloading programs), they crashed with this SSL error.

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

The problem was the version of python used :

问题是使用的python版本:

  1. No problem with https://www.python.org/downloadsand python-2.7.9-macosx10.6.pkg

  2. problem with the one instaled by Homebrew tool: "brew install python", version located in /usr/local/bin.

  1. https://www.python.org/downloads和 python-2.7.9-macosx10.6.pkg没问题

  2. Homebrew 工具安装的问题:“brew install python”,版本位于/usr/local/bin。

A chapter, called Certificate verification and OpenSSL [CHANGED for Python 2.7.9], in /Applications/Python 2.7/ReadMe.rtfexplains the problem with many details.

一章,叫Certificate verification and OpenSSL [CHANGED for Python 2.7.9],在/Applications/Python 2.7/ReadMe.rtf解释了很多细节问题。

So, check, download and put in your PATH the right version of python.

因此,请检查、下载并在 PATH 中放入正确版本的 python。

回答by Bruno Gabuzomeu

On Windows, Python does not look at the system certificate, it uses its own located at ?\lib\site-packages\certifi\cacert.pem.

在 Windows 上,Python 不查看系统证书,它使用自己位于?\lib\site-packages\certifi\cacert.pem.

The solution to your problem:

您的问题的解决方案:

  1. download the domain validation certificate as *.crt or *pem file
  2. open the file in editor and copy it's content to clipboard
  3. find your cacert.pemlocation: from requests.utils import DEFAULT_CA_BUNDLE_PATH; print(DEFAULT_CA_BUNDLE_PATH)
  4. edit the cacert.pemfile and paste your domain validation certificate at the end of the file.
  5. Save the file and enjoy requests!
  1. 将域验证证书下载为 *.crt 或 *pem 文件
  2. 在编辑器中打开文件并将其内容复制到剪贴板
  3. 找到您的cacert.pem位置:from requests.utils import DEFAULT_CA_BUNDLE_PATH; print(DEFAULT_CA_BUNDLE_PATH)
  4. 编辑cacert.pem文件并将您的域验证证书粘贴到文件末尾。
  5. 保存文件并享受请求!

回答by Ads

I hang my head in semi-shame, as I had the same issue, except that in my case, the URL I was hitting was valid, the certificate was valid. What wasn't valid was my connection out to the web. I had failed to add proxy details into the browser (IE in this case). This stopped the verification process from happening correctly.
Added in the proxy details and my python was then very happy .

我半惭愧地低下了头,因为我遇到了同样的问题,除了在我的情况下,我点击的 URL 是有效的,证书是有效的。无效的是我与网络的连接。我未能将代理详细信息添加到浏览器(在这种情况下为 IE)。这阻止了验证过程的正确发生。
添加了代理详细信息,然后我的 python 非常高兴。

回答by nobler1050

If your on vCenter 6, you should instead add your vCenter's vmware certificate authority cert to your OS's list of trusted CA's. To download your cert do the following

如果您使用的是 vCenter 6,则应将 vCenter 的 vmware 证书颁发机构证书添加到操作系统的受信任 CA 列表中。要下载您的证书,请执行以下操作

  1. Open your Web browser.
  2. Navigate to https://
  3. In the lower right-hand corner, click the Download Trusted Root CA link
  1. 打开您的网络浏览器。
  2. 导航到 https://
  3. 在右下角,单击下载受信任的根 CA 链接

On Fedora

在 Fedora 上

  1. unzip and change the extension from .0 to .cer
  2. Copy it to the /etc/pki/ca-trust/source/anchors/
  3. run the update-ca-trust command.
  1. 解压缩并将扩展名从 .0 更改为 .cer
  2. 将其复制到 /etc/pki/ca-trust/source/anchors/
  3. 运行 update-ca-trust 命令。

Links:

链接:

  1. https://virtualizationreview.com/articles/2015/04/02/install-root-self-signed-certificate-vcenter-6.aspx?m=1
  2. http://forums.fedoraforum.org/showthread.php?t=293856
  1. https://virtualizationreview.com/articles/2015/04/02/install-root-self-signed-certificate-vcenter-6.aspx?m=1
  2. http://forums.fedoraforum.org/showthread.php?t=293856

回答by Cherif KAOUA

For Python 3.4+on Centos 6/7,Fedora, just install the trusted CA this way :

对于Centos 6/7,Fedora上的Python 3.4+,只需以这种方式安装受信任的 CA:

  1. Copy the CA.crt to /etc/pki/ca-trust/source/anchors/
  2. update-ca-trust force-enable
  3. update-ca-trust extract
  1. 将 CA.crt 复制到 /etc/pki/ca-trust/source/anchors/
  2. update-ca-trust force-enable
  3. update-ca-trust extract

回答by caot

Python 2.7.12 (default, Jul 29 2016, 15:26:22) fixed the mentioned issue. This information might help someone else.

Python 2.7.12(默认,2016 年 7 月 29 日,15:26:22)修复了上述问题。此信息可能对其他人有所帮助。

回答by Prostak

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

Taken from here https://gist.github.com/michaelrice/a6794a017e349fc65d01

取自这里https://gist.github.com/michaelrice/a6794a017e349fc65d01

回答by Chris Halcrow

You could try adding this to your environment variables:

您可以尝试将其添加到您的环境变量中:

PYTHONHTTPSVERIFY=0 

Note that this will disable allHTTP verification so is a bit of a sledgehammer approach, however if verification isn't required it may be an effective solution.

请注意,这将禁用所有HTTP 验证,因此有点像大锤的方法,但是如果不需要验证,它可能是一个有效的解决方案。