2017-06-01 54 views
5

Używam API dla urządzenia Cisco CMXssl.SSLError: TLSv1 wersja alert protokół

(Patrz: 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)

i próbuje napisać kod Pythona, który sprawia, że ​​żądania GET do API Informacja. Kod jest następujący i jest taki sam jak w pliku, z wyjątkiem niezbędnych informacji zmienionych.

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() 

Jednak ja ciągle otrzymuję następujący błąd:

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) 

Próbowałem też aktualizowanie OpenSSL, ale to nie miało żadnego wpływu.

+1

Zobacz https://github.com/CiscoDevNet/devnet-express-dna-issues/issues/16. Wygląda na to, że używasz starej wersji OpenSSL w swoim Pythonie. Zazwyczaj ma to miejsce, jeśli używasz komputera Mac z naprawdę starą i nieaktualną wersją OpenSSL. –

+0

Wpadam na ten problem w oknach pobierających narzędzia binarne dla mikrokontrolera Wemos. Przyczyną było to, że google zabrał mi stronę pobierania wersji 2.7.3 (starej) Myślałem, że to najnowszy ... obecnie 2.7.14 jest najnowszym i już nie ma tego problemu, działa "automatycznie" . – Feri

Odpowiedz

7

Miałem ten sam błąd i google doprowadziło mnie do tego pytania, więc oto, co zrobiłem, mając nadzieję, że pomoże to innym w podobnej sytuacji.

ta ma zastosowanie dla OS X.

sprawdzić w terminalu, która wersja OpenSSL miałem:

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

Jak moja wersja OpenSSL było zbyt starych, zaakceptowane odpowiedź nie działa.

Musiałem więc zaktualizować OpenSSL. Aby to zrobić, zaktualizowane Pythona do najnowszej wersji (od wersji 3.5 do wersji 3.6) z Homebrew, po niektóre kroki sugerowane here:

$ brew update 
$ brew install openssl 
$ brew install python3 

Potem miał problemy ze ścieżką i wersję Pythona używany, więc po prostu stworzył nową virtualenv upewniając się, że najnowsza wersja Pythona została podjęta:

$ virtualenv webapp --python=python3.6 

Problem rozwiązany.

+1

Przyjęta odpowiedź sama w sobie tego nie w pełni pokryła, ale w komentarzach pośrednio wspomniałem o potrzebie aktualizacji OpenSSL. Przepraszam, że nie było to bardziej jasne i dzięki za dodanie tego! – finaris

+0

virtualenv rozwiązuje problem :) – karakays

+0

Jeśli ktoś nadal ma problemy, ten naprawdę mi pomógł: https://stackoverflow.com/a/46308535/1526702 –

2

Wierzę, że TLSV1_ALERT_PROTOCOL_VERSION ostrzega Cię, że serwer nie chce rozmawiać z Tobą TLS v1.0. Spróbuj określić TLS v1.2 tylko przez trzymanie w tych liniach: (? 2.7.9+ chyba)

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

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

Uwaga, może trzeba dostatecznie nowe wersje Pythona i ewentualnie OpenSSL (mam „OpenSSL 1.0.2k 26 stycznia 2017 "i powyższe wydaje się działać, YMMV)

+1

Czy działa OpenSSL 0.9.8 i TLS 1.2? Bardzo w to wątpię: TLS 1.2 jest obsługiwany tylko od OpenSSL 1.0.1. –

+0

TLS 1.2 nie działał z OpenSSL 0.9.8, ale zmieniłem interpreter na taki, na którym działały OpenSSL 1.0.2k i TLS 1.2 (a zatem połączenie z API powiodło się). – finaris

+1

@SteffenUllrich ah tak, robi 'python -c 'importuj ssl; print (ssl.OPENSSL_VERSION) "potwierdza, że ​​mój (zainstalowany homebrew) Python jest połączony z" OpenSSL 1.0.2k 26 sty 2017 ". Wersja 0.9.8zh, którą pokazałem, pochodziła z uruchomienia 'openssl version', która musi być moją starszą, ogólnosystemową instalacją. –

3

Żadna z zaakceptowanych odpowiedzi nie wskazała mi właściwego kierunku, a to wciąż jest pytanie, które pojawia się podczas przeszukiwania tematu, więc oto moja (częściowo) udana saga.

Tło: uruchamiam skrypt Pythona na czarnym Beaglebone, który odpytuje poloniex za pośrednictwem biblioteki python-poloniex. Nagle przestał działać z błędem TLSV1_ALERT_PROTOCOL_VERSION.

Okazało się, że OpenSSL było w porządku, a próba wymuszenia połączenia v1.2 była ogromnym pościgiem - biblioteka będzie używać najnowszej wersji, jeśli będzie to konieczne. Słabym ogniwem w łańcuchu był w rzeczywistości Python, który zdefiniował tylko ssl.PROTOCOL_TLSv1_2 i dlatego zaczął obsługiwać TLS v1.2 od wersji 3.4.

Tymczasem wersja Debiana na Beaglebone uważa najnowszy Python 3.3.Obejście Kiedyś było zainstalować Python 3.5 ze źródła (3,4 mogła ostatecznie pracował też, ale po wielu godzinach prób i błędów skończę):

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 

Może nie wszystkie te pakiety są bezwzględnie konieczne, ale instalacją one wszystkie naraz ratują masę ponownych prób. altinstall uniemożliwia instalowanie od zwierciadła istniejących binariów Pythona, instalując jako python3.5, ale to oznacza, że ​​musisz ponownie zainstalować dodatkowe biblioteki. The ./configure trwał dobre pięć lub dziesięć minut. make trwało kilka godzin.

Teraz to nadal nie działa, aż w końcu zabrakło

sudo -H pip3.5 install requests[security] 

który również instaluje pyOpenSSL, cryptography i idna. Podejrzewam, że kluczem był pyOpenSSL, więc być może pip3.5 install -U pyopenssl byłby wystarczający, ale już na tym poświęciłem zbyt wiele czasu, aby się upewnić.

Podsumowując, jeśli w Pythonie pojawi się błąd TLSV1_ALERT_PROTOCOL_VERSION, prawdopodobnie nie można w nim obsługiwać protokołu TLS v1.2. Aby dodać wsparcie, trzeba co najmniej następujące dane:

  • OpenSSL 1.0.1
  • Python 3.4
  • wnioski [Bezpieczeństwo]

To ma mnie obok TLSV1_ALERT_PROTOCOL_VERSION, a teraz mam zamiast tego walczyć z SSL23_GET_SERVER_HELLO.

Okazuje się, że powraca to do oryginalnego wydania Pythona wybierając niewłaściwą wersję SSL. Można to potwierdzić, używając triku this do zamontowania sesji żądań z ssl_version=ssl.PROTOCOL_TLSv1_2. Bez niego, SSLv23 jest używany i pojawia się błąd SSL23_GET_SERVER_HELLO. Wraz z nim żądanie się powiedzie.

Ostateczna bitwa polegała na wymuszeniu wybrania TLSv1_2, gdy żądanie zostało wykonane głęboko w bibliotece strony trzeciej. Zarówno this method, jak i this method powinny były zrobić lewy, ale nie zrobiły żadnej różnicy. Moje ostateczne rozwiązanie jest okropne, ale skuteczne. I edytowane /usr/local/lib/python3.5/site-packages/urllib3/util/ssl_.py i zmienił

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 

do

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 

i voila, mój skrypt może wreszcie ponownie skontaktować się z serwerem.

+0

Dziękujemy @Heath! Potwierdzam, że miałem ten sam problem z uruchomieniem Python2.7 i próbowałem połączyć się z Poloniex API, a samo uruchomienie 'pip install requests [security]' rozwiązało problem. Nie trzeba aktualizować do Python3 :) Bardzo doceniane! –