Ignorar la verificación del certificado de seguridad SSL en las solicitudes de Python
- Comprender el motivo detrás de las comprobaciones de seguridad SSL y por qué falla
- Ignorar la verificación de seguridad SSL en Python
- Conclusión
Acceder a una URL sin un certificado SSL seguro genera advertencias de excepción cuando se le envían solicitudes HTTP. Muchas veces, el certificado SSL de estas URL caduca, lo que crea todo tipo de problemas de seguridad.
Si la información no es confidencial, estas advertencias pueden atenuarse cuando los programas usan solicitudes
en Python. Este artículo proporcionará varias formas de desactivar las comprobaciones de certificados de seguridad mediante solicitudes
.
Comprender el motivo detrás de las comprobaciones de seguridad SSL y por qué falla
Si un programa utiliza solicitudes
de Python para obtener solicitudes de una URL cuyo certificado SSL ha caducado, genera dos excepciones. El siguiente programa muestra cuáles son esas excepciones.
escenario 1
Este programa utiliza una URL proporcionada por la comunidad SSL con un certificado de seguridad caducado con fines de prueba. Cabe señalar que las excepciones de seguridad SSL
solo surgen con URL que tienen certificados SSL
caducados.
Las peticiones
de Python no generan ninguna excepción con URLs con certificado SSL
válido o revocado. Por lo tanto, este artículo se centrará principalmente en las URL con certificados de seguridad caducados.
El siguiente ejemplo muestra un programa simple que importa solicitudes
en la primera línea. La segunda línea del programa envía una solicitud post
a la URL para modificar las apariciones de 'bar'
como 'baz'
.
Se hace para enviar una solicitud de publicación
a la URL y no tiene ningún otro significado dentro del programa.
import requests
requests.post(url="https://expired-rsa-dv.ssl.com/", data={"bar": "baz"})
La ejecución de este script de Python arroja excepciones SSLError
.
....
raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='expired-rsa-dv.ssl.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:841)'),))
Esta es la primera excepción a tener en cuenta al aprender a deshabilitar las comprobaciones de certificados de seguridad mediante solicitudes
.
Escenario 2
Este programa desactiva la verificación del certificado SSL
usando verify=False
para deshabilitar la verificación del certificado de seguridad usando requests
.
import requests
requests.post(url="https://expired-rsa-dv.ssl.com/", data={"bar": "baz"}, verify=False)
La biblioteca de solicitudes
está construida de manera que puede desactivar la verificación de certificados SSL
, pero el programa arroja otra excepción con enlaces que tienen certificados SSL
caducados.
InsecureRequestWarning: Unverified HTTPS request is being made to host 'expired-rsa-dv.ssl.com'. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html#ssl-warnings
InsecureRequestWarning,
Es necesario tratar estas dos excepciones para deshabilitar las comprobaciones de certificados de seguridad mediante solicitudes
.
Ignorar la verificación de seguridad SSL en Python
Esta sección explicará varios métodos que deshabilitan la verificación del certificado de seguridad usando solicitudes
o brindan una solución al problema. Cada método tiene su propósito.
Crea un Monkey Patch para la biblioteca requests
Si una biblioteca de terceros requiere que las comprobaciones de seguridad estén deshabilitadas, la biblioteca de solicitudes
puede ser monkey patched. Se utiliza un administrador de contexto para parchear para deshabilitar las comprobaciones de certificados de seguridad mediante solicitudes
.
Después de parchear las solicitudes
, el campo verificar
recibe un valor False
de forma predeterminada, lo que suprime la advertencia. Se lanza otra advertencia cuando se usa verify=false
, como se explica en el escenario 2 de la sección anterior.
Luego, el parche agregará un bloque de manejo de excepciones para deshabilitar la verificación del certificado de seguridad mediante solicitudes
y suprimirá las advertencias. Será más fácil de entender con los siguientes ejemplos.
El siguiente programa parchea la biblioteca de solicitudes
. Entendamos lo que hace este código.
Importaciones:
advertencias
: este paquete de biblioteca es un subpaquete de la bibliotecaExcepciones
.contextlib
: esta biblioteca de Python se utiliza para parchear la biblioteca desolicitudes
.solicitudes
: el paquete de biblioteca de solicitudes de Python.urllib3
: Es un módulo que maneja solicitudes HTTP y URLs en Python. Esta biblioteca se utiliza para importar un submóduloInsecureRequestWarning
, que genera una excepción para los certificadosSSL
caducados.
Parche:
Al principio, el programa guarda la configuración de entorno predeterminada de la biblioteca requests
en una variable: old_merge_environment_settings
. Esta variable se utilizará para devolver las solicitudes
a su estado predeterminado después de que se cierren los adaptadores abiertos.
old_merge_environment_settings = requests.Session.merge_environment_settings
El método no_ssl_verification
se crea y se adorna con @contextlib.contextmanager
. Se crea una nueva variable opened_adapters
y se le asigna un set()
.
Un conjunto es un tipo de datos que almacena elementos en un formato desordenado.
@contextlib.contextmanager
def no_ssl_verification():
opened_adapters = set()
Dentro del método no_ssl_verification
, se crea otro método anidado merge_environment_settings
. Este método tiene seis parámetros, similares a merge_environment_settings
del módulo requests
, y actuará como parche para el módulo original.
def merge_environment_settings(self, url, proxies, stream, verify, cert):
Dentro del método, la variable opened_adapters
se actualiza con el par de adaptadores coincidentes del parámetro url
. Cada conexión se realiza con algún par de adaptadores coincidentes, que se devuelven en este paso.
Dado que la verificación solo ocurre una vez por conexión, debemos cerrar todos los adaptadores abiertos una vez que hayamos terminado. De lo contrario, los efectos de verify=False
duran después de que finalice este administrador de contexto.
def merge_environment_settings(self, url, proxies, stream, verify, cert):
opened_adapters.add(self.get_adapter(url))
Es importante recordar la primera sección del artículo para comprender la siguiente línea de código. Cuando la función requests.post
se usó en la URL con un certificado SSL
caducado, arrojó dos excepciones.
La primera excepción fue causada por verificar
, que se establece con un valor True
. Aunque el campo verificar
era conmutable, se le podía dar un valor False
.
La segunda excepción fue una entidad no mutable que impidió que el programa estableciera una conexión.
El siguiente código modifica el campo verificar
para que tenga un valor False
por defecto para resolver este problema. Se crea una nueva variable settings
para ejecutar este paso, que se asigna con datos de la variable old_merge_environment_settings
.
Una vez que los datos se almacenan dentro de la variable configuración
, el campo verificar
se convierte en False
.
Esto cambia el valor predeterminado de verificar
. Por último, se devuelve esta variable.
settings = old_merge_environment_settings(self, url, proxies, stream, verify, cert)
settings["verify"] = False
return settings
Los datos del método actualizado merge_environment_settings
se asignan a la función requests.Session.merge_environment_settings
. Esto asegurará que el campo verificar
tenga un valor False
por defecto.
requests.Session.merge_environment_settings = merge_environment_settings
Nos hemos ocupado de la primera excepción. La segunda excepción, que no es mutable, se resolverá mediante un bloque de manejo de excepciones.
Entendamos lo que hace el código aquí.
En un primer momento, dentro del bloque try
, se crea un bloque with
que recoge todas las advertencias emitidas. Dentro de este bloque with
, la función warnings.simplefilter
se usa para dar un valor ignorar
al submódulo urllib3
InsecureRequestWarning
.
Como aprendimos en la sección de importaciones, el submódulo InsecureRequestWarning
genera una excepción para los certificados SSL
que caducan; asignarle un valor ignorar
omitirá la segunda excepción causada.
try:
with warnings.catch_warnings():
warnings.simplefilter('ignore', InsecureRequestWarning)
yield
Dentro del bloque finally
, la configuración original almacenada dentro de old_merge_environment_settings
se vuelve a asignar a la función requests.Session.merge_environment_settings
.
Como todos los adaptadores abiertos deben cerrarse antes de que el programa salga, se crea un bucle for
que itera la cantidad de veces que los adaptadores abiertos están dentro del programa.
Todos los adaptadores se cierran usando la función adapter.close()
usando un bloque try-except
; dentro del bloque excepto
, se pasa la iteración.
for adapter in opened_adapters:
try:
adapter.close()
except:
pass
El código completo se da a continuación.
import warnings
import contextlib
import requests
from urllib3.exceptions import InsecureRequestWarning
old_merge_environment_settings = requests.Session.merge_environment_settings
@contextlib.contextmanager
def no_ssl_verification():
opened_adapters = set()
def merge_environment_settings(self, url, proxies, stream, verify, cert):
opened_adapters.add(self.get_adapter(url))
settings = old_merge_environment_settings(
self, url, proxies, stream, verify, cert
)
settings["verify"] = False
return settings
requests.Session.merge_environment_settings = merge_environment_settings
try:
with warnings.catch_warnings():
warnings.simplefilter("ignore", InsecureRequestWarning)
yield
finally:
requests.Session.merge_environment_settings = old_merge_environment_settings
for adapter in opened_adapters:
try:
adapter.close()
except:
pass
Usa Monkey Patch en Python
El parche de mono se puede invocar utilizando el método no_ssl_verification()
. Cualquier solicitud enviada bajo este método seguirá las directivas del parche de mono y deshabilitará las verificaciones de certificados de seguridad usando solicitudes
.
Veamos un ejemplo.
El método no_ssl_verification
se llama bajo un bloque with
. Esto ejecutará el método dentro del bloque y luego se cerrará cuando el compilador salga del bloque.
Dentro del bloque, se envía una llamada requests.get
a la URL con un certificado SSL
caducado. Con la configuración predeterminada, esto habría causado un lanzamiento de excepción, pero esta vez la llamada requests.get
se envía con éxito.
Se envía otra solicitud con las solicitudes
, donde el campo verificar
se establece en True
. A diferencia del escenario predeterminado, esta vez no se lanza ninguna excepción de error.
with no_ssl_verification():
requests.get("https://expired-rsa-dv.ssl.com/")
print("Modifications working Properly")
requests.get("https://expired-rsa-dv.ssl.com/", verify=True)
print("`Verify=true` has its meaning changed")
Producción :
Modifications working Properly
`Verify=true` has its meaning changed
Se vio que Verify=False
tenía las directivas para restablecer el parche con la configuración predeterminada. Cuando este campo se configuró dentro de requests.get()
, el parche del mono se restablece a la configuración predeterminada, lo que permite generar excepciones de error.
requests.get("https://expired-rsa-dv.ssl.com/", verify=False)
print("It resets back")
Producción :
connectionpool.py:1052: InsecureRequestWarning: Unverified HTTPS request is being made to host 'expired-rsa-dv.ssl.com'.
InsecureRequestWarning,
It resets back
El submódulo solicitudes
sesión
también se puede utilizar con el parche de mono.
En una variable llamada sesión
, se carga la función solicitudes.Sesión()
. El valor session.verify
se establece en True
.
Dentro de un bloque with
, la función session.get()
se usa para enviar la solicitud get
a la URL, y el campo verify
se establece en True
. Una declaración de print
imprime un mensaje si se realiza la conexión.
session = requests.Session()
session.verify = True
with no_ssl_verification():
session.get("https://expired-rsa-dv.ssl.com/", verify=True)
print("Works in Session")
Producción :
Works in Session
Cuando el administrador de contexto sale, este código cierra cualquier adaptador abierto que maneje una solicitud parcheada. Dado que requests
mantiene un grupo de conexiones para cada sesión y la validación del certificado solo ocurre una vez por conexión, ocurrirán eventos inesperados como los siguientes.
try:
requests.get("https://expired-rsa-dv.ssl.com/", verify=False)
except requests.exceptions.SSLError:
print("It breaks")
try:
session.get("https://expired-rsa-dv.ssl.com/")
except requests.exceptions.SSLError:
print("It breaks here again")
Producción :
C:\Users\Win 10\venv\lib\site-packages\urllib3\connectionpool.py:1052: InsecureRequestWarning: Unverified HTTPS request is being made to host 'expired-rsa-dv.ssl.com'.
InsecureRequestWarning,
It breaks here again
Use urllib3
para deshabilitar las advertencias en Python
Si el programa requiere deshabilitar las verificaciones de certificados de seguridad sin usar “solicitudes” o parches mono, entonces usar urllib3
proporciona una solución simple.
Importa requests
y urllib3
, y desde urllib3
importa el submódulo InsecureRequestWarning
. La advertencia se deshabilita mediante la función urllib3.disable_warnings
.
La instrucción requests.post()
se coloca debajo del bloque try
, y el campo verify
se establece en False
. Esto deshabilitará la comprobación de seguridad de los certificados de seguridad caducados.
Dentro del bloque excepto
, aparece SSLError
con un mensaje de error.
import requests
from urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
try:
requests.post(
url="https://expired-rsa-dv.ssl.com/", data={"bar": "baz"}, verify=False
)
print("Connection made successfully")
except requests.exceptions.SSLError:
print("Expired Certificate")
Producción :
Connection made successfully
Conclusión
Este artículo explica varios métodos para deshabilitar las comprobaciones de certificados de seguridad mediante solicitudes
en Python. El lector, a través del artículo, puede desactivar fácilmente los controles de seguridad.