python - simple - ssl tlsv1_alert_protocol_version tlsv1 alert protocol version(_ ssl c 600 skipping
ssl.SSLError: versiĆ³n del protocolo de alerta tlsv1 (7)
A partir de julio de 2018, Pypi ahora requiere que los clientes que se conectan a él usen TLS 1.2. Este es un problema si está utilizando la versión de Python incluida con MacOS (2.7.10) porque solo es compatible con TLS 1.0. Puede cambiar la versión de SSL que Python está utilizando para solucionar el problema o actualizar a una versión más nueva de Python. Use homebrew para instalar la nueva versión de python fuera de la ubicación predeterminada de la biblioteca.
brew install python@2
Estoy usando la API REST para un dispositivo Cisco CMX e intento escribir el código Python que realiza una solicitud GET a la API para obtener información. El código es el siguiente y es el mismo que el del archivo, excepto con la información necesaria modificada.
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()
Sin embargo, continuamente recibo el siguiente error:
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)
También intenté actualizar OpenSSL pero eso no tuvo ningún efecto.
Creo que
TLSV1_ALERT_PROTOCOL_VERSION
está alertando de que el servidor no quiere hablarte TLS v1.0.
Intente especificar TLS v1.2 solo pegándose en estas líneas:
import ssl
context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
# Create HTTPS connection
c = HTTPSConnection("0.0.0.0", context=context)
Tenga en cuenta que es posible que necesite versiones suficientemente nuevas de Python (2.7.9+ ¿quizás?) Y posiblemente OpenSSL (tengo "OpenSSL 1.0.2k 26 de enero de 2017" y lo anterior parece funcionar, YMMV)
Lo único que debe hacer es instalar
requests[security]
en su virtualenv.
No debería tener que usar Python 3 (debería funcionar en Python 2.7).
Además, si está utilizando una versión reciente de macOS, tampoco tiene que usar
homebrew
para instalar OpenSSL por separado.
$ 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]
permite que las solicitudes utilicen la última versión de TLS al negociar la conexión.
El openssl incorporado en macOS es compatible con TLS v1.2.
Antes de instalar su propia versión de OpenSSL, haga esta pregunta: ¿cómo se carga Google Chrome https://github.com ?
Ninguna de las respuestas aceptadas me señaló en la dirección correcta, y esta sigue siendo la pregunta que surge al buscar el tema, así que aquí está mi saga (parcialmente) exitosa.
Antecedentes: ejecuto un script de Python en un Beaglebone Black que sondea el intercambio de criptomonedas Poloniex usando la biblioteca python-poloniex . De repente dejó de funcionar con el error TLSV1_ALERT_PROTOCOL_VERSION.
Resulta que OpenSSL estaba bien, e intentar forzar una conexión v1.2 fue una gran persecución: la biblioteca usará la última versión según sea necesario.
El eslabón débil de la cadena era en realidad Python, que solo definía
ssl.PROTOCOL_TLSv1_2
y, por lo tanto, comenzó a admitir TLS v1.2, desde la versión 3.4.
Mientras tanto, la versión de Debian en Beaglebone considera Python 3.3 como la última. La solución alternativa que utilicé fue instalar Python 3.5 desde el origen (3.4 podría haber funcionado también, pero después de horas de prueba y error he terminado):
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
Tal vez no todos esos paquetes sean estrictamente necesarios, pero instalarlos todos a la vez ahorra un montón de reintentos.
El
altinstall
evita que la instalación bloquee los binarios existentes de python, instalando como
python3.5
, aunque eso significa que debe reinstalar bibliotecas adicionales.
La
./configure
tardó unos buenos cinco o diez minutos.
El
make
tomó un par de horas.
Ahora esto todavía no funcionó hasta que finalmente corrí
sudo -H pip3.5 install requests[security]
Que también instala
pyOpenSSL
,
cryptography
e
idna
.
Sospecho que
pyOpenSSL
fue la clave, por lo que tal vez
pip3.5 install -U pyopenssl
hubiera sido suficiente, pero ya he pasado demasiado tiempo en esto para asegurarme.
En resumen, si obtiene el error TLSV1_ALERT_PROTOCOL_VERSION en Python, probablemente sea porque no puede admitir TLS v1.2. Para agregar soporte, necesita al menos lo siguiente:
- OpenSSL 1.0.1
- Python 3.4
- solicitudes [seguridad]
Esto me ha pasado TLSV1_ALERT_PROTOCOL_VERSION, y ahora puedo luchar con SSL23_GET_SERVER_HELLO en su lugar.
Resulta que esto es volver al problema original de Python seleccionando la versión SSL incorrecta.
Esto se puede confirmar utilizando
this
truco para montar una sesión de solicitudes con
ssl_version=ssl.PROTOCOL_TLSv1_2
.
Sin él, se usa SSLv23 y aparece el error SSL23_GET_SERVER_HELLO.
Con ello, la solicitud tiene éxito.
La batalla final fue forzar la selección de TLSv1_2 cuando la solicitud se realiza en una biblioteca de terceros.
Tanto
este método
como
este método
deberían haber hecho el truco, pero ninguno hizo ninguna diferencia.
Mi solución final es horrible, pero efectiva.
Edité
/usr/local/lib/python3.5/site-packages/urllib3/util/ssl_.py
y cambié
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
a
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
y listo, mi script finalmente puede contactar al servidor nuevamente.
Para Mac OS X
1) Actualice a Python 3.6.5 utilizando el instalador de aplicaciones nativo descargado del sitio web oficial del lenguaje Python https://www.python.org/downloads/
Descubrí que el instalador se encarga de actualizar los enlaces y enlaces simbólicos para el nuevo Python mucho mejor que homebrew.
2) Instale un nuevo certificado usando "./Install Certificates.command" que se encuentra en el directorio actualizado de Python 3.6
> cd "/Applications/Python 3.6/"
> sudo "./Install Certificates.command"
Tengo este problema también. En macos, aquí está la solución:
-
Paso 1: preparar reiniciar Python. ahora tienes python3.7 en lugar de la vieja python
-
Paso 2: compila la nueva base env en python3.7. mi ruta es
/usr/local/Cellar/python/3.7.2/bin/python3.7
ahora, no te molestará este problema.
Tuve el mismo error y Google me llevó a esta pregunta, así que esto es lo que hice, con la esperanza de que ayude a otros en una situación similar.
Esto es aplicable para OS X.
Comprueba en el Terminal qué versión de OpenSSL tenía:
$ python3 -c "import ssl; print(ssl.OPENSSL_VERSION)"
>> OpenSSL 0.9.8zh 14 Jan 2016
Como mi versión de OpenSSL era demasiado antigua, la respuesta aceptada no funcionó.
Entonces tuve que actualizar OpenSSL. Para hacer esto, actualicé Python a la última versión (de la versión 3.5 a la versión 3.6) con Homebrew, siguiendo algunos de los pasos sugeridos here :
$ brew update
$ brew install openssl
$ brew install python3
Luego estaba teniendo problemas con el PATH y la versión de python que estaba usando, así que creé un nuevo
virtualenv
asegurándome de que se tomara la versión más nueva de python:
$ virtualenv webapp --python=python3.6
Problema resuelto.