ssl.SSLError:tlsv1警报协议版本

时间:2017-06-01 20:10:38

标签: python ssl https cisco

我正在为Cisco CMX device使用REST API,并尝试编写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()

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

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)

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

10 个答案:

答案 0 :(得分:50)

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

这适用于OS X.

在终端检查我有哪个版本的OpenSSL:

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

由于我的OpenSSL版本太旧,所接受的答案无效。

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

$ brew update
$ brew install openssl
$ brew install python3

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

$ virtualenv webapp --python=python3.6

问题已解决。

答案 1 :(得分:21)

您唯一需要做的就是在您的virtualenv中安装requests[security]。您不应该使用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]允许请求在协商连接时使用最新版本的TLS。 macOS上的内置openssl支持TLS v1.2。

  

在安装自己的OpenSSL版本之前,请先提出以下问题:Google Chrome如何加载https://github.com

答案 2 :(得分:8)

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

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

事实证明OpenSSL很好,并试图强制v1.2连接是一个巨大的疯狂追逐 - 图书馆将根据需要使用最新版本。链中的弱链接实际上是Python,它只定义了ssl.PROTOCOL_TLSv1_2,因此从版本3.4开始支持TLS v1.2。

与此同时,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

也许不是所有这些包都是必需的,但是一次安装它们可以省去一堆重试。 altinstall阻止安装破坏现有的python二进制文件,而是安装为python3.5,但这确实意味着您必须重新安装其他库。 ./configure花了五到十分钟。 make花了几个小时。

现在,在我最终运行

之前,这仍然无效
sudo -H pip3.5 install requests[security]

其中还会安装pyOpenSSLcryptographyidna。我怀疑pyOpenSSL是关键所在,所以也许pip3.5 install -U pyopenssl已经足够了,但我已经花了很长时间才确定这一点。

总而言之,如果在Python中出现TLSV1_ALERT_PROTOCOL_VERSION错误,可能是因为您无法支持TLS v1.2。要添加支持,您至少需要以下内容:

  • OpenSSL 1.0.1
  • Python 3.4
  • 请求[安全]

这让我超越了TLSV1_ALERT_PROTOCOL_VERSION,现在我开始与SSL23_GET_SERVER_HELLO作战。

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

最后一场战斗是在第三方库中深入请求时强制选择TLSv1_2。 this methodthis method都应该完成这个伎俩,但两者都没有任何区别。我的最终解决方案是可怕的,但有效。我编辑了/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

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

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

答案 3 :(得分:7)

我相信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)

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

答案 4 :(得分:4)

对于Mac OS X

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

我发现安装程序正在处理更新新Python的链接和符号链接比自制程序更好。

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

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

答案 5 :(得分:2)

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

brew install python@2

答案 6 :(得分:1)

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

我通过更改进行了修复

context = ssl.SSLContext(ssl.PROTOCOL_TLSv1)

context = ssl.SSLContext()

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

Debian 10没有这个问题。

答案 7 :(得分:0)

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

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

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

现在,您将不会受到此问题的困扰。

答案 8 :(得分:0)

当我尝试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)

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

答案 9 :(得分:0)

对于 MacOS 上的 python2 用户(找不到python @ 2公式),因为brew停止了对python2的支持,您需要使用这样的命令! 但是不要忘记取消链接旧的python(如果已预先安装)。

brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/86a44a0a552c673a05f11018459c9f5faae3becc/Formula/python@2.rb

如果您犯了一些错误,只需brew uninstall python@2旧方法,然后再试一次。

thank you hyperknot (answer here)