Cómo verificar los certificados SSL utilizando la biblioteca requests en Python

La biblioteca requests de Python se utiliza ampliamente para facilitar el uso de APIs web y la comunicación HTTP. Sin embargo, para garantizar una comunicación segura, la encriptación mediante el protocolo SSL/TLS es crucial. Aunque la biblioteca requests verifica los certificados SSL de manera predeterminada, pueden surgir errores dependiendo del entorno. Para manejar correctamente los errores de certificados y mantener la seguridad de la comunicación, es esencial entender el mecanismo de verificación de los certificados SSL y configurarlo adecuadamente. Este artículo explica de manera clara cómo verificar los certificados SSL usando la biblioteca requests y cómo solucionar problemas comunes.

Índice

Conceptos básicos sobre la verificación de certificados SSL


El certificado SSL (Secure Sockets Layer) es un mecanismo que cifra la comunicación entre un servidor web y un cliente para evitar el espionaje y la manipulación por parte de terceros. Actualmente, el protocolo TLS (Transport Layer Security), sucesor de SSL, es el estándar dominante, aunque se sigue utilizando comúnmente el término “certificado SSL”.

El funcionamiento de los certificados SSL


Un certificado SSL es obtenido por el administrador del sitio web de una autoridad certificadora (CA), y sirve para demostrar que el sitio es confiable. Cuando los navegadores o clientes HTTP realizan una comunicación SSL/TLS, verifican el certificado para asegurar lo siguiente:

  1. Que el emisor del certificado es una CA confiable.
  2. Que el nombre del dominio al que se refiere el certificado coincide con el dominio solicitado.
  3. Que el certificado no ha expirado.

Importancia de la verificación de certificados


Verificar el certificado SSL ayuda a prevenir los siguientes riesgos de seguridad:

  • Suplantación de identidad: Previene que un servidor falso robe los datos del usuario.
  • Ataques de intermediarios (MITM): Reduce el riesgo de que la comunicación sea escuchada o manipulada.

Verificar los certificados de manera adecuada es crucial para garantizar una comunicación segura. La biblioteca requests también está diseñada para realizar esta verificación por defecto.

Configuración básica de verificación SSL en la biblioteca requests

La biblioteca requests cuenta con una funcionalidad automática para verificar los certificados SSL. Esto garantiza la seguridad de la comunicación y asegura que solo se establezca conexión con sitios web confiables.

El rol del parámetro `verify`


En la biblioteca requests, se usa el parámetro verify para controlar la verificación de los certificados SSL. Este parámetro tiene dos configuraciones posibles:

  1. True (predeterminado): Habilita la verificación del certificado.
  2. False: Deshabilita la verificación del certificado (no recomendado).

El comportamiento predeterminado es verify=True, lo que significa que la verificación del certificado se realiza consultando una lista de CAs confiables.

Uso básico


A continuación se muestra un ejemplo de cómo utilizar el parámetro verify.

import requests

# Verificar el certificado SSL y enviar la solicitud HTTPS
response = requests.get('https://example.com', verify=True)
print(response.status_code)

Cómo deshabilitar la verificación del certificado


Si deseas deshabilitar la verificación del certificado para pruebas o depuración, puedes configurarlo de la siguiente manera:

import requests

# Enviar solicitud sin verificar el certificado SSL (no recomendado)
response = requests.get('https://example.com', verify=False)
print(response.status_code)

En este caso, Python generará una advertencia. También puedes suprimir la advertencia, aunque esto no debe hacerse en un entorno de producción.

import requests
from requests.packages.urllib3.exceptions import InsecureRequestWarning

# Suprimir advertencias
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

# Enviar solicitud sin verificar el certificado SSL
response = requests.get('https://example.com', verify=False)
print(response.status_code)

Precauciones


Deshabilitar la verificación del certificado aumenta los riesgos de seguridad. Se puede establecer una conexión con un sitio malicioso o ser víctima de un ataque de intermediario, por lo que el uso de verify=False debe limitarse a entornos de prueba o situaciones específicas.

Deshabilitar el certificado SSL y los riesgos asociados

Deshabilitar la verificación del certificado SSL puede evitar errores de comunicación, pero esto conlleva graves riesgos de seguridad. En la biblioteca requests, al especificar verify=False, se omite la verificación del certificado, pero su uso en entornos de producción no es recomendado.

Cómo deshabilitar la verificación del certificado SSL


Para deshabilitar la verificación del certificado, configura verify=False.

import requests

# Deshabilitar la verificación SSL
response = requests.get('https://example.com', verify=False)
print(response.text)

Con esta configuración, la solicitud se enviará sin verificar la validez del certificado.

Riesgos de deshabilitar la verificación del certificado

  1. Vulnerabilidad a los ataques de intermediarios (MITM)
    Si deshabilitas la verificación, puedes establecer conexión con un servidor no confiable. Un atacante malicioso podría interceptar y modificar los datos.
  2. Conexión con un servidor suplantado
    Si un tercero malicioso se hace pasar por el servidor legítimo, la conexión puede establecerse sin problemas, lo que incrementa el riesgo de fuga de información sensible.
  3. Explotación de vulnerabilidades
    Ignorar el protocolo de seguridad SSL/TLS puede permitir la comunicación con servidores vulnerables que usan métodos de encriptación obsoletos.

Ignorar advertencias y los riesgos adicionales


Las advertencias en requests están diseñadas para alertar sobre posibles riesgos. Suprimir estas advertencias con urllib3.disable_warnings podría ocultar problemas de seguridad importantes.

# Suprimir advertencias no recomendadas
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

Recomendaciones


En lugar de deshabilitar la verificación del certificado, considera resolver el problema de las siguientes maneras:

  • Instalar certificados CA confiables: Asegúrate de que el certificado del servidor esté correctamente emitido.
  • Configurar certificados personalizados: Especifica un certificado CA personalizado con el parámetro verify (se explica más adelante).
  • Configuración adecuada del servidor: Asegúrate de que el servidor esté usando un certificado SSL válido.

Deshabilitar la verificación del certificado debe ser una medida temporal, utilizada solo para depuración o para resolver problemas específicos, asegurando siempre que la conexión sea segura.

Verificación SSL con certificados personalizados

En algunos casos, puede ser necesario conectar a un servidor que use un certificado SSL emitido por una autoridad certificadora (CA) personalizada. En estos casos, se puede especificar un archivo de certificado personalizado mediante el parámetro verify en la biblioteca requests para realizar la verificación del certificado.

Preparar un certificado CA personalizado


Para usar un certificado CA personalizado, primero debes obtener ese certificado (generalmente en formato .pem) y guardarlo en tu entorno local. Supongamos que tenemos un archivo de certificado llamado my_ca_cert.pem.

Cómo usar un certificado personalizado


En la biblioteca requests, puedes especificar la ruta del archivo de certificado en el parámetro verify de la siguiente manera:

import requests

# Usar un certificado CA personalizado para la solicitud
response = requests.get('https://example.com', verify='path/to/my_ca_cert.pem')
print(response.status_code)

Con esta configuración, la verificación del certificado del servidor se realizará utilizando el certificado CA especificado.

Consideraciones sobre la cadena de certificados


Si el certificado CA personalizado requiere certificados intermedios, asegúrate de que la cadena de certificados esté configurada correctamente. Si el archivo my_ca_cert.pem incluye los certificados intermedios necesarios, la verificación tendrá más posibilidades de éxito.

Ejemplo de verificación exitosa


A continuación se muestra un ejemplo exitoso de cómo usar un certificado personalizado para enviar una solicitud HTTPS:

# Si el certificado es correcto
response = requests.get('https://securedomain.com', verify='my_ca_cert.pem')
if response.ok:
    print("¡Conexión exitosa!")
else:
    print("Fallo en la conexión. Código de estado:", response.status_code)

Qué hacer si el certificado personalizado no es reconocido

  1. Verificar el formato del certificado
    Asegúrate de que el certificado esté codificado en formato PEM. Si el formato es diferente, puedes convertirlo usando OpenSSL.
   openssl x509 -in my_ca_cert.crt -out my_ca_cert.pem -outform PEM
  1. Verificar la ruta del certificado
    Asegúrate de que la ruta del archivo del certificado esté correctamente especificada.
  2. Integrar la cadena de certificados
    Si se requieren certificados intermedios, intégralos en el archivo principal del certificado CA.
   cat intermediate_cert.pem >> my_ca_cert.pem

Uso del certificado en todo el sistema


Si usas frecuentemente certificados personalizados, considera agregar el certificado al almacén de certificados predeterminado del sistema. Esto puede ayudarte a mantener la conexión segura y simplificar tu código.

sudo cp my_ca_cert.pem /usr/local/share/ca-certificates/
sudo update-ca-certificates

Recomendaciones


Incluso al usar certificados personalizados, siempre verifica la confiabilidad de los certificados. Usar certificados bien gestionados ayuda a mantener la comunicación segura.

Cómo resolver los errores de certificado

Cuando se usan los certificados SSL en la biblioteca requests, pueden ocurrir errores de certificado. Estos errores pueden deberse a un certificado incorrecto o a un problema con el entorno del sistema. A continuación, explicamos las causas comunes de los errores de certificado y sus soluciones.

Errores comunes y sus causas

  1. Certificado no confiable (Certificate verify failed)
    Este error ocurre cuando el certificado del servidor no está firmado por una autoridad certificadora (CA) o cuando el certificado CA no está en el almacén de confianza del sistema.
   requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED]
  1. Certificado caducado (Expired certificate)
    Este error ocurre cuando el certificado del servidor ha caducado.
  2. Incompatibilidad del nombre del dominio (Hostname mismatch)
    Este error ocurre cuando el nombre del dominio del certificado (Common Name o SAN) no coincide con el nombre de dominio de la URL solicitada.
  3. Falta de certificados intermedios (Incomplete certificate chain)
    Este error ocurre cuando el servidor no proporciona los certificados intermedios necesarios.

Soluciones para los errores

1. Agregar un certificado CA


Cuando un certificado no es confiable, puedes proporcionar un certificado CA personalizado utilizando el parámetro verify.

import requests

# Usar un certificado CA personalizado
response = requests.get('https://example.com', verify='path/to/ca_cert.pem')
print(response.status_code)

2. Actualizar el almacén de certificados CA del sistema


Si el almacén de certificados del sistema está desactualizado, puedes actualizarlo mediante los siguientes comandos.

  • Debian/Ubuntu
  sudo apt update
  sudo apt install --reinstall ca-certificates
      security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain path/to/ca_cert.pem

    3. Verificar el certificado del servidor


    Si el certificado del servidor está caducado o tiene un nombre de dominio incompatible, debes contactar al administrador del servidor para que actualice o corrija el certificado. Puedes usar el comando openssl para verificar el certificado.

    openssl s_client -connect example.com:443 -showcerts

    4. Integrar certificados intermedios


    Si faltan certificados intermedios, asegúrate de que la cadena de certificados esté completa.

    cat intermediate_cert.pem >> server_cert.pem

    5. Solución temporal (no recomendada)


    Si necesitas evitar el error de certificado, puedes deshabilitar la verificación configurando verify=False, aunque no se recomienda en entornos de producción.

    response = requests.get('https://example.com', verify=False)

    Mejores prácticas para resolver errores

    • Actualiza regularmente el almacén de certificados CA del sistema.
    • Verifica que el servidor esté configurado correctamente con el certificado adecuado.
    • Usa certificados CA personalizados cuando sea necesario para garantizar una comunicación segura.

    Con estas medidas, puedes resolver eficazmente los errores relacionados con los certificados SSL y asegurar una comunicación segura.

    Verificación de certificados usando herramientas externas

    Para resolver problemas relacionados con los certificados SSL, es útil verificar los detalles del certificado y determinar la causa del problema. No solo puedes usar la biblioteca requests, sino también herramientas externas para investigar los certificados. Aquí exploramos herramientas que te pueden ayudar a comprobar los certificados y cómo usarlas.

    Verificación de certificados con OpenSSL

    OpenSSL es una herramienta ampliamente utilizada para la gestión de certificados y la comunicación SSL/TLS. Puedes utilizarla para obtener el certificado del servidor y verificar problemas.

    Obtener el certificado del servidor


    Con el siguiente comando puedes obtener el certificado de un servidor específico y ver los detalles:

    openssl s_client -connect example.com:443 -showcerts

    Ejemplo de salida:

    Certificate chain
     0 s:/CN=example.com
       i:/CN=Example CA
    ---
    Server certificate
    -----BEGIN CERTIFICATE-----
    (certificado de datos)
    -----END CERTIFICATE-----

    Verificar la fecha de vencimiento del certificado


    Para verificar la fecha de vencimiento de un certificado, utiliza el siguiente comando:

    openssl x509 -in server_cert.pem -noout -dates

    Ejemplo de salida:

    notBefore=Nov  1 00:00:00 2023 GMT
    notAfter=Oct 31 23:59:59 2024 GMT

    Verificación de certificados CA usando certifi

    La biblioteca requests de Python usa por defecto la biblioteca certifi para gestionar los certificados CA confiables. Con certifi puedes verificar la lista actual de certificados CA.

    Instalar certifi


    Si no tienes instalado certifi, puedes instalarlo con el siguiente comando:

    pip install certifi

    Verificar la ruta de los certificados usando certifi


    Para verificar la ruta del certificado CA que estás utilizando, puedes ejecutar el siguiente código:

    import certifi
    
    # Mostrar la ruta del certificado CA
    print(certifi.where())

    Ejemplo de salida:

    /path/to/python/site-packages/certifi/cacert.pem

    Verificación de certificados usando el navegador

    También puedes verificar los certificados SSL directamente desde tu navegador. En Chrome o Firefox, sigue estos pasos:

    1. Acceder al sitio web: Visita el sitio web objetivo (por ejemplo: https://example.com).
    2. Mostrar información del certificado:
    • Chrome: Haz clic en el ícono de candado en la barra de direcciones y selecciona “Detalles”.
    • Firefox: Haz clic en el ícono de candado y selecciona “Detalles de la conexión”.
    1. Verificar los detalles del certificado: Revisa el emisor, el dominio objetivo y la fecha de vencimiento.

    Puntos clave en la verificación

    • Coincidencia del nombre de dominio: Verifica que el CN o SAN del certificado coincidan con el nombre de dominio al que accedes.
    • Existencia de certificados intermedios: Verifica que la cadena de certificados esté completa y que todos los certificados intermedios estén presentes.
    • Fecha de vencimiento: Verifica que el certificado no haya expirado.

    Guía para elegir herramientas

    • Para obtener el certificado directamente del servidor: usa OpenSSL.
    • Para verificar la lista de CA confiables de requests: usa certifi.
    • Para ver la información del certificado de manera intuitiva: usa el navegador.

    Al usar estas herramientas, puedes identificar problemas relacionados con los certificados SSL y obtener la información necesaria para mantener un entorno de comunicación seguro.

    Ejemplo práctico de verificación SSL con requests

    En este apartado, mostramos ejemplos reales de código para verificar certificados SSL utilizando la biblioteca requests de Python. Cubriremos desde el método básico de verificación hasta el uso de certificados personalizados.

    Ejemplo básico de verificación SSL

    La biblioteca requests verifica los certificados SSL de forma predeterminada. A continuación, mostramos un ejemplo de cómo enviar una solicitud HTTPS utilizando esta configuración predeterminada.

    import requests
    
    # Solicitud HTTPS que verifica el certificado correctamente
    url = 'https://www.google.com'
    response = requests.get(url)
    
    print(f"Código de estado: {response.status_code}")
    print(f"Cabeceras de respuesta: {response.headers}")

    Este código muestra el código de estado HTTP y las cabeceras de respuesta si la verificación del certificado es exitosa.

    Ejemplo de error de verificación SSL

    Si la verificación del certificado falla, se generará un requests.exceptions.SSLError. A continuación, mostramos un ejemplo en el que se utiliza un sitio con un certificado autofirmado.

    url = 'https://self-signed.badssl.com'
    
    try:
        response = requests.get(url)
    except requests.exceptions.SSLError as e:
        print(f"Error de verificación SSL: {e}")

    Este ejemplo generará un error debido a un certificado autofirmado que no es confiable.

    Ejemplo con certificado CA personalizado

    A continuación se muestra cómo utilizar un certificado CA personalizado para verificar el certificado del servidor.

    url = 'https://example.com'
    ca_cert_path = '/path/to/your/ca_cert.pem'
    
    # Enviar solicitud especificando un certificado personalizado
    response = requests.get(url, verify=ca_cert_path)
    
    print(f"Código de estado: {response.status_code}")
    print(f"Cuerpo de respuesta: {response.text}")

    Este código muestra cómo especificar la ruta del archivo del certificado personalizado para verificar el certificado del servidor.

    Ejemplo de deshabilitación de la verificación SSL (no recomendado)

    Este ejemplo muestra cómo deshabilitar la verificación SSL para enviar una solicitud, lo cual no se recomienda fuera de entornos de prueba.

    url = 'https://self-signed.badssl.com'
    
    # Deshabilitar la verificación y enviar solicitud
    response = requests.get(url, verify=False)
    
    print(f"Código de estado: {response.status_code}")
    print(f"Cuerpo de respuesta: {response.text}")

    Este código envía la solicitud sin verificar el certificado SSL, generando una advertencia de seguridad en Python.

    Ejemplo con registros detallados de verificación SSL

    Cuando se produce un error en la verificación del certificado, habilitar los registros detallados puede proporcionar información útil para la depuración.

    import requests
    import logging
    
    # Activar registro detallado
    logging.basicConfig(level=logging.DEBUG)
    
    url = 'https://www.google.com'
    response = requests.get(url)
    
    print(f"Código de estado: {response.status_code}")

    Los registros proporcionarán información detallada sobre el proceso de verificación SSL, incluyendo el handshake TLS y detalles del certificado.

    Ejemplo general para manejar múltiples casos

    A continuación se presenta una función que maneja la verificación SSL, permitiendo alternar entre la verificación predeterminada, el uso de un certificado personalizado y la deshabilitación de la verificación.

    def fetch_url(url, ca_cert=None, disable_ssl=False):
        try:
            if disable_ssl:
                response = requests.get(url, verify=False)
            elif ca_cert:
                response = requests.get(url, verify=ca_cert)
            else:
                response = requests.get(url)
            return response.text
        except requests.exceptions.SSLError as e:
            return f"Error SSL: {e}"
        except Exception as e:
            return f"Otro error: {e}"
    
    # Ejemplos de uso
    print(fetch_url('https://example.com', ca_cert='/path/to/ca_cert.pem'))
    print(fetch_url('https://self-signed.badssl.com', disable_ssl=True))

    Esta función utiliza el parámetro verify para permitir distintas configuraciones de verificación SSL.

    Comprobación de resultados

    Al ejecutar el código, asegúrate de verificar lo siguiente:

    • Si la comunicación fue exitosa.
    • Si el código de estado y el contenido de la respuesta son correctos.
    • Si se obtiene información detallada cuando ocurre un error.

    Usando estos ejemplos, podrás manejar múltiples escenarios relacionados con la verificación de certificados SSL.

    Ejemplo avanzado: Verificación de certificados SSL en comunicaciones API

    En las comunicaciones API, la verificación de certificados SSL es especialmente importante para evitar conexiones a servidores no confiables y para asegurar que los datos se transmitan de forma segura. A continuación, mostramos ejemplos prácticos de verificación SSL en comunicaciones API.

    Verificación SSL en API que requieren autenticación

    Muchos servicios API requieren autenticación mediante tokens o claves API. El siguiente ejemplo muestra cómo enviar una solicitud con autenticación y verificación SSL habilitada.

    import requests
    
    api_url = 'https://api.example.com/data'
    api_key = 'your_api_key_here'
    
    headers = {
        'Authorization': f'Bearer {api_key}',
        'Content-Type': 'application/json'
    }
    
    # Enviar solicitud HTTPS
    response = requests.get(api_url, headers=headers)
    
    if response.status_code == 200:
        print("Datos obtenidos exitosamente:", response.json())
    else:
        print(f"Error: {response.status_code}, Detalles: {response.text}")

    Este código envía una solicitud a una API con autenticación, asegurando que la verificación del certificado SSL esté activa durante la comunicación.

    Comunicación con API interna utilizando certificados personalizados

    En sistemas internos o APIs privadas, se puede utilizar un certificado CA personalizado. Aquí se muestra cómo especificar un certificado personalizado al realizar una solicitud API.

    api_url = 'https://internal-api.example.com/data'
    ca_cert_path = '/path/to/internal_ca_cert.pem'
    
    # Usar certificado personalizado
    response = requests.get(api_url, verify=ca_cert_path)
    
    if response.status_code == 200:
        print("Comunicación con API interna exitosa:", response.json())
    else:
        print(f"Error: {response.status_code}, Detalles: {response.text}")

    Comunicación de prueba con verificación SSL deshabilitada

    En un entorno de desarrollo, a veces se utilizan certificados autofirmados. En estos casos, puedes deshabilitar la verificación SSL, aunque esto debe limitarse a entornos de prueba.

    api_url = 'https://dev-api.example.com/data'
    
    # Deshabilitar verificación SSL en la solicitud
    response = requests.get(api_url, verify=False)
    
    if response.status_code == 200:
        print("Comunicación de prueba exitosa:", response.json())
    else:
        print(f"Error: {response.status_code}, Detalles: {response.text}")

    Mejores prácticas de seguridad

    Para llevar a cabo la verificación SSL de forma segura en las comunicaciones API, sigue estas mejores prácticas:

    1. Mantén siempre la verificación SSL habilitada


    Evita usar verify=False fuera de entornos de prueba para evitar la conexión a servidores no confiables.

    2. Verifica regularmente la validez del certificado


    Supervisa regularmente los certificados en uso para asegurarte de que no hayan expirado.

    openssl x509 -in /path/to/certificate.pem -noout -dates

    3. Implementa un manejo adecuado de errores


    En caso de error SSL, implementa un manejo de excepciones adecuado para registrar detalles sobre los problemas.

    try:
        response = requests.get(api_url, verify=True)
        response.raise_for_status()
    except requests.exceptions.SSLError as e:
        print(f"Error SSL: {e}")
    except requests.exceptions.RequestException as e:
        print(f"Error de comunicación: {e}")

    4. Usa certificados de cliente cuando sea necesario


    En las APIs que requieren autenticación de cliente, utiliza certificados de cliente.

    api_url = 'https://secure-api.example.com/data'
    client_cert = '/path/to/client_cert.pem'
    client_key = '/path/to/client_key.pem'
    
    response = requests.get(api_url, cert=(client_cert, client_key), verify=True)
    
    if response.status_code == 200:
        print("Autenticación de cliente exitosa:", response.json())
    else:
        print(f"Error: {response.status_code}, Detalles: {response.text}")

    Resumen

    • Configuración adecuada de verificación SSL: Da prioridad a la seguridad utilizando el parámetro verify para garantizar comunicaciones seguras.
    • Manejo adecuado de errores: Mantén un registro detallado de los errores para facilitar la resolución de problemas.
    • Uso de certificados personalizados: Utiliza certificados CA o de cliente personalizados para garantizar comunicaciones internas seguras.

    Al implementar estos métodos, puedes realizar verificaciones SSL en las comunicaciones API de forma segura y eficiente.

    Resumen

    Este artículo explica cómo verificar los certificados SSL utilizando la biblioteca requests en Python. Los certificados SSL juegan un papel fundamental en garantizar la seguridad de las comunicaciones. Hemos cubierto desde la configuración básica de requests hasta el uso de certificados personalizados, la resolución de errores y ejemplos prácticos de comunicación API.

    Asegúrate de aplicar los puntos clave para mantener comunicaciones seguras:

    • Usa la configuración predeterminada de verificación SSL para garantizar comunicaciones seguras.
    • Especifica certificados CA personalizados cuando trabajes con comunicaciones internas.
    • Desactiva la verificación SSL solo en entornos de prueba y siempre habilítala en producción.

    Usa estos conocimientos para lograr comunicaciones HTTP más seguras y confiables.

Índice