Estoy tratando de obtener datos de la web usando python. Importé el paquete urllib.request para él, pero durante la ejecución, aparece el error:
certificate verify failed: unable to get local issuer certificate (_ssl.c:1045)Cuando cambié la URL a 'http', puedo obtener datos. Pero, creo, esto evita verificar el certificado SSL.
Así que busqué en Internet y encontré una solución: Ejecutar /Applications/Python\ 3.7/Install\ Certificates.command
Esto resolvió mi problema. Pero no tengo conocimiento sobre SSL y similares. ¿Pueden ayudarme a entender lo que realmente hizo para resolver mi problema?
Si es posible, recomiéndeme algún buen recurso para obtener información sobre la seguridad y los certificados. Soy nuevo en esto.
¡Gracias!
Nota: Revisé el enlace: openssl, error de solicitud de python: "falló la verificación del certificado"
Mi pregunta difiere de la del enlace porque quiero saber qué sucede realmente cuando instalo el paquete certifi o ejecuto Install\ Certificates.command para corregir el error. Tengo una pobre comprensión de los valores.
Para cualquiera que todavía se pregunte cómo solucionar esto, obtuve el mío instalando el comando " Install Certificates.command ".
Así es como lo hice,
Simplemente haga doble clic en ese archivo, espere a que se instale y, en mi caso, estará listo para comenzar.
Encontré el mismo problema en OSX, mientras que mi código estaba totalmente bien en Linux, ¡y usted dio la respuesta en su pregunta!
Después de inspeccionar el archivo que apuntó a /Applications/Python 3.7/Install Certificates.command , resultó que este comando reemplaza los certificados raíz de la instalación predeterminada de Python con los que se envían a través del paquete certifi .
certifi es un conjunto de certificados raíz. Cada certificado SSL se basa en una cadena de confianza: usted confía en un certificado específico porque confía en el padre de ese certificado, para lo cual confía en el padre, etc. En algún momento, no hay un "padre" y esos son certificados "raíz". Para esos, no hay otra solución que agrupar certificados raíz comúnmente confiables (generalmente grandes compañías de confianza como, por ejemplo, "DigiCert").
Por ejemplo, puede ver los certificados raíz en la configuración de seguridad de su navegador (por ejemplo, para Firefox->Preferencias->Privacidad y seguridad->ver certificados->Autoridades).
Volviendo al problema inicial, y antes de ejecutar el archivo .command , ejecutar esto me devuelve una lista vacía en una instalación limpia:
import os import ssl openssl_dir, openssl_cafile = os.path.split( ssl.get_default_verify_paths().openssl_cafile) # no content in this folder os.listdir(openssl_dir) # non existent file print(os.path.exists(os.path.join(openssl_dir, openssl_cafile))) Esto significa que no existe una autoridad de certificación predeterminada para la instalación de Python en OSX. Un posible valor predeterminado es exactamente el proporcionado por el paquete certifi .
Después de eso, solo puede crear un contexto SSL que tenga el valor predeterminado adecuado como el siguiente ( certifi.where() proporciona la ubicación de una autoridad de certificación):
import platform # ... ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS) ssl_context.verify_mode = ssl.CERT_REQUIRED ssl_context.check_hostname = True ssl_context.load_default_certs() if platform.system().lower() == 'darwin': import certifi ssl_context.load_verify_locations( cafile=os.path.relpath(certifi.where()), capath=None, cadata=None) y haga una solicitud a una url de python como esta:
import urllib # previous context https_handler = urllib.request.HTTPSHandler(context=ssl_context) opener = urllib.request.build_opener(https_handler) ret = opener.open(url, timeout=2)Esto funcionó en todos los sistemas operativos:
import ssl import certifi from urllib.request import urlopen request = "https://example.com" urlopen(request, context=ssl.create_default_context(cafile=certifi.where()))