【问题标题】:ssl.SSLError: tlsv1 alert protocol versionssl.SSLError:tlsv1 警报协议版本
【发布时间】:2017-11-03 02:51:37
【问题描述】:

我将 REST API 用于Cisco CMX device,并尝试编写 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,但没有效果。

【问题讨论】:

  • github.com/CiscoDevNet/devnet-express-dna-issues/issues/16。看起来您在 Python 中使用的是旧版本的 OpenSSL。如果您使用的是带有非常旧且过时版本的 OpenSSL 的 Mac,通常会出现这种情况。
  • 我在 windows 上遇到了这个问题,为 wemos 微控制器获取二进制工具。原因是谷歌给我的python 2.7.3(旧)版本下载页面我认为它是最新的......目前2.7.14是最新的,它不再有这个问题,它“自动”工作.
  • 对于所有pip installs 都收到此错误[SSL: TLSV1_ALERT_PROTOCOL_VERSION] 的人来说,这是因为Python.org 网站最近弃用了TLS。见this answer

标签: python ssl https cisco


【解决方案1】:

我相信TLSV1_ALERT_PROTOCOL_VERSION 正在提醒您服务器不想与您交谈 TLS v1.0。尝试仅通过坚持以下几行来指定 TLS v1.2:

import ssl
from http.client import HTTPSConnection
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 26 Jan 2017”,上面的似乎工作,YMMV)

【讨论】:

  • 你有 OpenSSL 0.9.8 和 TLS 1.2 的作品吗?我非常怀疑这一点:自 OpenSSL 1.0.1 起才支持 TLS 1.2。
  • TLS 1.2 不适用于 OpenSSL 0.9.8,但我将解释器更改为支持 OpenSSL 1.0.2k 和 TLS 1.2 的解释器(因此对 API 的调用成功)。跨度>
  • @SteffenUllrich 啊,是的,做python -c 'import ssl; print(ssl.OPENSSL_VERSION)' 确认我的(安装了自制软件)Python 与“OpenSSL 1.0.2k 2017 年 1 月 26 日”相关联。我显示的 0.9.8zh 版本字符串来自运行 openssl version,这一定是我较旧的系统范围安装。
【解决方案2】:

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

这适用于 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

问题已解决。

【讨论】:

  • 接受的答案本身并没有完全涵盖它,但在我间接提到需要更新 OpenSSL 的 cmets 中。抱歉,这不是更清楚,感谢您添加此内容!
  • 如果有人仍然有问题,这个真的帮助了我:stackoverflow.com/a/46308535/1526702
  • 请参考我下面的回答。我通过安装 requests[security] 解决了我的问题,没有使用 Python3,也没有使用 brew 安装 openssl。
  • 升级到 3.6 也解决了 Windows 10 上的问题。谢谢。
  • 您好,我无法更新到 python3,因为脚本需要 python2.7(从 cocos2dx 下载-deps.py),有什么建议吗?
【解决方案3】:

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

背景:我在 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

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

【讨论】:

  • 谢谢@Heath!我确认我在运行 Python2.7 并尝试连接到 Poloniex API 时遇到了同样的问题,并且运行 pip install requests[security] 解决了这个问题。无需升级到 Python3 :) 非常感谢!
【解决方案4】:

您唯一需要做的就是在您的 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 的?

【讨论】:

  • James,你有什么版本的 MacOS (sw_vers) ? xmlrpclib -&gt; httplib -&gt; ssl 对你有用吗,就像在 searching-pypi-by-topicpypi = ... https: ... 不是 http 一样?
  • @denis OS 版本应该没有 OpenSSL 版本那么重要,您可以通过 ssl.OPENSSL_VERSION 获得。
  • pip install 'requests[security]' 完成了这项工作,谢谢。
  • 谢谢,这解决了我在本地使用多个 python 版本进行测试时遇到的所有问题。
【解决方案5】:

适用于 Mac OS X

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

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

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

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

【讨论】:

  • 起初这对我不起作用(在其他方法也不起作用之后,所以我对使用 Python 3 的前景非常失望)但是 sudo 命令的部分初始失败结果表明我使用 sudo 的 -H 标志。这样做,顺利更新。
【解决方案6】:

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

brew install python@2

【讨论】:

  • 你用这个答案真的拯救了我的一天。我可以给你买啤酒吗?请PM我你的BTC地址。老实说,我现在在 El Capitan 下运行了一个 Python 脚本(我知道,我不应该再使用它了,但在那种情况下我必须这样做),这给我带来了巨大的飞跃。谢谢!!!
【解决方案7】:

我也遇到了这个问题。 在macos中,解决方法如下:

  • 第 1 步:重新安装 python。现在你得到了 python3.7 而不是旧的 python

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

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

【讨论】:

    【解决方案8】:

    我在尝试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】:

    这个问题的另一个来源:我发现在 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 没有这个问题。

    【讨论】:

    • 这也适用于 Ubuntu 18.04 LTS。此处描述的相同修复方法有效。
    【解决方案10】:

    对于 MacOS (找不到 python@2 公式) 上的 python2 用户,因为 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)

    【讨论】:

      【解决方案11】:

      我在使用带有 flask_mqtt 扩展名的 Flask 时遇到了这个问题。解决方案是将其添加到 Python 文件中:

      app.config['MQTT_TLS_VERSION'] = ssl.PROTOCOL_TLSv1_2 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-06-05
        • 1970-01-01
        • 1970-01-01
        • 2018-12-15
        • 1970-01-01
        • 2019-04-08
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多