Python ssl.SSLError: tlsv1 警报协议版本

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/44316292/
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 23:55:13  来源:igfitidea点击:

ssl.SSLError: tlsv1 alert protocol version

pythonsslhttpscisco

提问by finaris

I'm using the REST API for a Cisco CMX device, and trying to write Python code which makes a GET request to the API for information. The code is as follows and is the same as that in the file except with the necessary information changed.

我正在将 REST API 用于Cisco CMX 设备,并尝试编写 Python 代码,该代码向 API 发出 GET 请求以获取信息。代码如下,除了必要的信息有所改变外,与文件中的代码相同。

from http.client import HTTPSConnection
from base64 import b64encode


# Create HTTPS connection
c = HTTPSConnection("0.0.0.0")

# encode as Base64
# decode to ascii (python3 stores as byte string, need to pass as ascii 
value for auth)
username_password = b64encode(b"admin:password").decode("ascii")
headers = {'Authorization': 'Basic {0}'.format(username_password)}

# connect and ask for resource
c.request('GET', '/api/config/v1/aaa/users', headers=headers)

# response
res = c.getresponse()

data = res.read()

However, I am continuously getting the following error:

但是,我不断收到以下错误:

Traceback (most recent call last):
  File "/Users/finaris/PycharmProjects/test/test/test.py", line 14, in <module>
    c.request('GET', '/api/config/v1/aaa/users', headers=headers)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 1106, in request
    self._send_request(method, url, body, headers)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 1151, in _send_request
    self.endheaders(body)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 1102, in endheaders
    self._send_output(message_body)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 934, in _send_output
    self.send(msg)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 877, in send
    self.connect()
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/http/client.py", line 1260, in connect
    server_hostname=server_hostname)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/ssl.py", line 377, in wrap_socket
    _context=self)
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/ssl.py", line 752, in __init__
    self.do_handshake()
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/ssl.py", line 988, in do_handshake
    self._sslobj.do_handshake()
  File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/ssl.py", line 633, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:645)

I also tried updating OpenSSL but that had no effect.

我也尝试更新 OpenSSL,但没有效果。

回答by J0ANMM

I had the same error and google brought me to this question, so here is what I did, hoping that it helps others in a similar situation.

我有同样的错误,谷歌把我带到了这个问题,所以这就是我所做的,希望它可以帮助处于类似情况的其他人。

This is applicable for OS X.

这适用于 OS X。

Check in the Terminal which version of OpenSSL I had:

在终端中检查我拥有的 OpenSSL 版本:

$ python3 -c "import ssl; print(ssl.OPENSSL_VERSION)"
>> OpenSSL 0.9.8zh 14 Jan 2016

As my version of OpenSSL was too old, the accepted answer did not work.

由于我的 OpenSSL 版本太旧,接受的答案不起作用。

So I had to update OpenSSL. To do this, I updated Python to the latest version (from version 3.5 to version 3.6) with Homebrew, following some of the steps suggested here:

所以我不得不更新 OpenSSL。为此,我使用 Homebrew 将 Python 更新到最新版本(从 3.5 版到 3.6 版),遵循此处建议的一些步骤:

$ brew update
$ brew install openssl
$ brew install python3

Then I was having problems with the PATH and the version of python being used, so I just created a new virtualenvmaking sure that the newest version of python was taken:

然后我遇到了 PATH 和正在使用的 python 版本的问题,所以我刚刚创建了一个新的,virtualenv以确保采用最新版本的 python:

$ virtualenv webapp --python=python3.6

Issue solved.

问题解决了。

回答by James Lim

The only thing you have to do is to install requests[security]in your virtualenv. You should not have to use Python 3 (it should work in Python 2.7). Moreover, if you are using a recent version of macOS, you don't have to use homebrewto separately install OpenSSL either.

您唯一需要做的就是安装requests[security]在您的 virtualenv 中。你不应该使用 Python 3(它应该在 Python 2.7 中工作)。此外,如果您使用的是最新版本的 macOS,您也不必homebrew单独安装 OpenSSL。

$ virtualenv --python=/usr/bin/python tempenv  # uses system python
$ . tempenv/bin/activate
$ pip install requests
$ python
>>> import ssl
>>> ssl.OPENSSL_VERSION
'OpenSSL 0.9.8zh 14 Jan 2016'  # this is the built-in openssl
>>> import requests
>>> requests.get('https://api.github.com/users/octocat/orgs')
requests.exceptions.SSLError: HTTPSConnectionPool(host='api.github.com', port=443): Max retries exceeded with url: /users/octocat/orgs (Caused by SSLError(SSLError(1, u'[SSL: TLSV1_ALERT_PROTOCOL_VERSION] tlsv1 alert protocol version (_ssl.c:590)'),))
$ pip install 'requests[security]'
$ python  # install requests[security] and try again
>>> import requests
>>> requests.get('https://api.github.com/users/octocat/orgs')
<Response [200]>

requests[security]allows requests to use the latest version of TLS when negotiating the connection. The built-in openssl on macOS supports TLS v1.2.

requests[security]允许请求在协商连接时使用最新版本的 TLS。macOS 上的内置 openssl 支持 TLS v1.2。

Before you install your own version of OpenSSL, ask this question: how is Google Chrome loading https://github.com?

在安装自己的 OpenSSL 版本之前,先问这个问题:Google Chrome 是如何加载https://github.com 的

回答by Josh Kupershmidt

I believe TLSV1_ALERT_PROTOCOL_VERSIONis alerting you that the server doesn't want to talk TLS v1.0 to you. Try to specify TLS v1.2 only by sticking in these lines:

我相信TLSV1_ALERT_PROTOCOL_VERSION是在提醒您服务器不想与您谈论 TLS v1.0。尝试仅通过粘贴以下行来指定 TLS v1.2:

import ssl
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)

# Create HTTPS connection
c = HTTPSConnection("0.0.0.0", context=context)

Note, you may need sufficiently new versions of Python (2.7.9+ perhaps?) and possibly OpenSSL (I have "OpenSSL 1.0.2k 26 Jan 2017" and the above seems to work, YMMV)

请注意,您可能需要足够新的 Python 版本(也许是 2.7.9+?),也可能需要 OpenSSL(我有“OpenSSL 1.0.2k 26 Jan 2017”,以上似乎有效,YMMV)

回答by Heath Raftery

None of the accepted answers pointed me in the right direction, and this is still the question that comes up when searching the topic, so here's my (partially) successful saga.

没有一个接受的答案为我指明了正确的方向,这仍然是搜索主题时出现的问题,所以这是我(部分)成功的传奇。

Background: I run a Python script on a Beaglebone Black that polls the cryptocurrency exchange Poloniex using the python-poloniexlibrary. It suddenly stopped working with the TLSV1_ALERT_PROTOCOL_VERSION error.

背景:我在 Beaglebone Black 上运行 Python 脚本,该脚本使用python-poloniex库轮询加密货币交易所 Poloniex 。它突然停止工作,出现 TLSV1_ALERT_PROTOCOL_VERSION 错误。

Turns out that OpenSSL was fine, and trying to force a v1.2 connection was a huge wild goose chase - the library will use the latest version as necessary. The weak link in the chain was actually Python, which only defined ssl.PROTOCOL_TLSv1_2, and therefore started supporting TLS v1.2, since version 3.4.

事实证明,OpenSSL 很好,并且试图强制建立 v1.2 连接是一场巨大的追逐——该库将根据需要使用最新版本。链中的薄弱环节实际上是 Python,它只定义了ssl.PROTOCOL_TLSv1_2,因此从 3.4 版开始支持 TLS v1.2。

Meanwhile, the version of Debian on the Beaglebone considers Python 3.3 the latest. The workaround I used was to install Python 3.5 from source (3.4 might have eventually worked too, but after hours of trial and error I'm done):

同时,Beaglebone 上的 Debian 版本认为 Python 3.3 是最新的。我使用的解决方法是从源代码安装 Python 3.5(3.4 最终可能也能正常工作,但经过数小时的反复试验我完成了):

sudo apt-get install build-essential checkinstall
sudo apt-get install libreadline-gplv2-dev libncursesw5-dev libssl-dev libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev
wget https://www.python.org/ftp/python/3.5.4/Python-3.5.4.tgz
sudo tar xzf Python-3.5.4.tgz
cd Python-3.5.4
./configure
sudo make altinstall

Maybe not all those packages are strictly necessary, but installing them all at once saves a bunch of retries. The altinstallprevents the install from clobbering existing python binaries, installing as python3.5instead, though that does mean you have to re-install additional libraries. The ./configuretook a good five or ten minutes. The maketook a couple of hours.

也许并非所有这些包都是绝对必要的,但是一次安装它们可以节省大量重试。这altinstall可以防止安装破坏现有的 python 二进制文件,python3.5而是安装,尽管这确实意味着您必须重新安装其他库。在./configure花了好五到十分钟。在make花了几个小时。

Now this still didn't work until I finally ran

现在这仍然没有用,直到我终于跑了

sudo -H pip3.5 install requests[security]

Which also installs pyOpenSSL, cryptographyand idna. I suspect pyOpenSSLwas the key, so maybe pip3.5 install -U pyopensslwould have been sufficient but I've spent far too long on this already to make sure.

它还安装pyOpenSSL,cryptographyidna. 我怀疑pyOpenSSL是关键,所以也许pip3.5 install -U pyopenssl已经足够了,但我已经花了太长时间来确定。

So in summary, if you get TLSV1_ALERT_PROTOCOL_VERSION error in Python, it's probably because you can't support TLS v1.2. To add support, you need at least the following:

所以总结一下,如果你在 Python 中得到 TLSV1_ALERT_PROTOCOL_VERSION 错误,那可能是因为你不能支持 TLS v1.2。要添加支持,您至少需要以下内容:

  • OpenSSL 1.0.1
  • Python 3.4
  • requests[security]
  • OpenSSL 1.0.1
  • 蟒蛇 3.4
  • 请求[安全]

This has got me past TLSV1_ALERT_PROTOCOL_VERSION, and now I get to battle with SSL23_GET_SERVER_HELLO instead.

这让我超越了 TLSV1_ALERT_PROTOCOL_VERSION,现在我开始使用 SSL23_GET_SERVER_HELLO。

Turns out this is back to the original issue of Python selecting the wrong SSL version. This can be confirmed by using thistrick to mount a requests session with ssl_version=ssl.PROTOCOL_TLSv1_2. Without it, SSLv23 is used and the SSL23_GET_SERVER_HELLO error appears. With it, the request succeeds.

原来这又回到了 Python 选择错误 SSL 版本的原始问题。这可以通过使用技巧安装请求会话来确认ssl_version=ssl.PROTOCOL_TLSv1_2。没有它,将使用 SSLv23 并出现 SSL23_GET_SERVER_HELLO 错误。有了它,请求就成功了。

The final battle was to force TLSv1_2 to be picked when the request is made deep within a third party library. Both this methodand this methodought to have done the trick, but neither made any difference. My final solution is horrible, but effective. I edited /usr/local/lib/python3.5/site-packages/urllib3/util/ssl_.pyand changed

最后的战斗是在第三方库深处发出请求时强制选择 TLSv1_2。无论这种方法这种方法应该做的伎俩,但没有取得任何区别。我的最终解决方案很糟糕,但很有效。我编辑/usr/local/lib/python3.5/site-packages/urllib3/util/ssl_.py和更改

def resolve_ssl_version(candidate):
    """
    like resolve_cert_reqs
    """
    if candidate is None:
        return PROTOCOL_SSLv23

    if isinstance(candidate, str):
        res = getattr(ssl, candidate, None)
        if res is None:
            res = getattr(ssl, 'PROTOCOL_' + candidate)
        return res

    return candidate

to

def resolve_ssl_version(candidate):
    """
    like resolve_cert_reqs
    """
    if candidate is None:
        return ssl.PROTOCOL_TLSv1_2

    if isinstance(candidate, str):
        res = getattr(ssl, candidate, None)
        if res is None:
            res = getattr(ssl, 'PROTOCOL_' + candidate)
        return res

    return candidate

and voila, my script can finally contact the server again.

瞧,我的脚本终于可以再次联系服务器了。

回答by BenJi

As of July 2018, Pypi now requires that clients connecting to it use TLS 1.2. This is an issue if you're using the version of python shipped with MacOS (2.7.10) because it only supports TLS 1.0. You can change the version of ssl that python is using to fix the problem or upgrade to a newer version of python. Use homebrew to install the new version of python outside of the default library location.

截至 2018 年 7 月,Pypi 现在要求连接到它的客户端使用 TLS 1.2。如果您使用的是 MacOS (2.7.10) 附带的 python 版本,这是一个问题,因为它仅支持 TLS 1.0。您可以更改 python 用于修复问题的 ssl 版本或升级到更新版本的 python。使用 homebrew 在默认库位置之外安装新版本的 python。

brew install python@2

回答by Claude COULOMBE

For Mac OS X

对于 Mac OS X

1) Update to Python 3.6.5 using the native app installer downloaded from the official Python language website https://www.python.org/downloads/

1) 使用从 Python 语言官方网站https://www.python.org/downloads/下载的本机应用程序安装程序更新到 Python 3.6.5

I've found that the installer is taking care of updating the links and symlinks for the new Python a lot better than homebrew.

我发现安装程序负责更新新 Python 的链接和符号链接比自制软件要好得多。

2) Install a new certificate using "./Install Certificates.command" which is in the refreshed Python 3.6 directory

2) 使用“./Install Certificates.command”安装新证书,它位于刷新后的 Python 3.6 目录中

> cd "/Applications/Python 3.6/"
> sudo "./Install Certificates.command"

回答by Maestro Pu

I got this problem too. In macos, here is the solution:

我也遇到了这个问题。在 macos 中,这是解决方案:

  • Step 1: brew restall python. now you got python3.7 instead of the old python

  • Step 2: build the new env base on python3.7. my path is /usr/local/Cellar/python/3.7.2/bin/python3.7

  • 步骤1:酿造restall python。现在你得到了 python3.7 而不是旧的 python

  • 第二步:基于python3.7构建新的env。我的路是/usr/local/Cellar/python/3.7.2/bin/python3.7

now, you'll not being disturbed by this problem.

现在,你不会被这个问题打扰了。

回答by mrmicrowaveoven

I encountered this exact issue when I attempted gem install bundler, and I was confused by all the Python responses (since I was using Ruby). Here was my exact error:

我在尝试时遇到了这个确切的问题gem install bundler,并且对所有 Python 响应感到困惑(因为我使用的是 Ruby)。这是我的确切错误:

ERROR:  Could not find a valid gem 'bundler' (>= 0), here is why:
          Unable to download data from https://rubygems.org/ - SSL_connect returned=1 errno=0 state=SSLv2/v3 read server hello A: tlsv1 alert protocol version (https://rubygems.org/latest_specs.4.8.gz)

My solution: I updated Ruby to the most recent version (2.6.5). Problem solved.

我的解决方案:我将 Ruby 更新到最新版本 (2.6.5)。问题解决了。

回答by giraffedata

Another source of this problem: I found that in Debian 9, the Python httplib2is hardcoded to insist on TLS v1.0. So any application that uses httplib2to connect to a server that insists on better security fails with TLSV1_ALERT_PROTOCOL_VERSION.

这个问题的另一个来源:我发现在 Debian 9 中,Python httplib2被硬编码为坚持 TLS v1.0。因此,任何使用httplib2连接到坚持更高安全性的服务器的应用程序都会因TLSV1_ALERT_PROTOCOL_VERSION 而失败。

I fixed it by changing

我通过改变来修复它

context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)

to

context = ssl.SSLContext()

in /usr/lib/python3/dist-packages/httplib2/__init__.py .

在 /usr/lib/python3/dist-packages/httplib2/__init__.py 中。

Debian 10 doesn't have this problem.

Debian 10 没有这个问题。