2017-06-01 167 views
5

我使用API​​的思科CMX设备ssl.SSLError:警惕的TLSv1协议版本

(参见:https://www.cisco.com/c/en/us/td/docs/wireless/mse/10-2/api/b_cg_CMX_REST_API_Getting_Started_Guide/b_cg_CMX_REST_API_Getting_Started_Guide_chapter_01.html

,并努力写出Python代码,这使得GET请求的API信息。代码如下,除了必要的信息已更改外,其余与文件中的代码相同。

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但没有任何效果。

+1

请参阅https://github.com/CiscoDevNet/devnet-express-dna-issues/issues/16。看起来你正在Python中使用旧版本的OpenSSL。如果您使用的是随旧版OpenSSL发布的Mac,则通常会出现这种情况。 –

+0

我在windows上得到wemos微控制器的二进制工具时遇到了这个问题。原因是谷歌带我的蟒蛇2.7.3(旧)版本的下载页面我认为这是最新的...目前2.7.14是最新的,它不再有这个问题了,它的作品“自动” 。 – Feri

回答

7

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

这适用于OS X.

检查接线我有其中的OpenSSL版本:

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

由于我的OpenSSL的版本是太旧了,该接受的答案没有工作。

所以我不得不更新OpenSSL。要做到这一点,我更新的Python到最新版本(从3.5版到3.6版)与自制,以下一些步骤建议here

$ brew update 
$ brew install openssl 
$ brew install python3 

然后我在与PATH问题和python的版本正在使用的,所以我刚刚创建了一个新的virtualenv确保蟒蛇最新版本的拍摄:

$ virtualenv webapp --python=python3.6 

问题解决。

+1

接受的答案本身并没有完全覆盖它,但在间接提到的需要更新OpenSSL的评论中。道歉,这不是更清楚,并感谢加入! – finaris

+0

virtualenv解决了这个问题:) – karakays

+0

如果有人仍然有问题,这一个真的帮助我:https://stackoverflow.com/a/46308535/1526702 –

2

我相信TLSV1_ALERT_PROTOCOL_VERSION被提醒您的是,服务器并不想谈论TLS V1.0给你。尝试仅仅在这些行坚持以指定TLS V1.2:(?2.7.9+也许)

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

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

注意,你可能需要的Python足够的新版本,并可能OpenSSL的(我有“的OpenSSL 1.0.2k 2017" 年1月26日和上面似乎工作,因人而异)

+1

你有OpenSSL 0.9.8和TLS 1.2的作品?我非常怀疑这一点:自OpenSSL 1.0.1以来,仅支持TLS 1.2。 –

+0

TLS 1.2不能与OpenSSL 0.9.8一起使用,但我将解释器更改为OpenSSL 1.0.2k和TLS 1.2工作正常(并因此调用API成功)的解释器。 – finaris

+1

@SteffenUllrich啊是的,在做'python -c'import ssl;打印(SSL。OPENSSL_VERSION)''确认我的(已安装自制软件)Python与“OpenSSL 1.0.2k 2017年1月26日”链接。我展示的0.9.8zh版本字符串来自运行'openssl version',它必须是我较早的系统级安装。 –

3

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

背景:我在Beaglebone黑色运行Python脚本,轮询cryptocurrency交换Poloniex使用python-poloniex库。它突然停止与TLSV1_ALERT_PROTOCOL_VERSION错误工作。

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

同时,Debian的对Beaglebone版本认为的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 

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

+0

谢谢@海瑟!我确认我运行Python2.7时遇到了同样的问题,并尝试连接到Poloniex API,只是运行'pip install requests [security]'解决了问题。无需升级到Python3 :)非常感谢! –