2017-06-01 126 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 :)非常感謝! –