Instalé un certificado CA raíz autofirmado en /usr/share/ca-certificates/local
de Debian y lo instalé con sudo dpkg-reconfigure ca-certificates
. En este punto true | gnutls-cli mysite.local
es feliz y true | openssl s_client -connect mysite.local:443
está satisfecho, pero el módulo de solicitudes de python2 y python3 insiste en que no está satisfecho con el certificado.
pitón2:
Traceback (most recent call last): File "<string>", line 1, in <module> File "/usr/local/lib/python2.7/site-packages/requests/api.py", line 70, in get return request('get', url, params=params, **kwargs) File "/usr/local/lib/python2.7/site-packages/requests/api.py", line 56, in request return session.request(method=method, url=url, **kwargs) File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 488, in request resp = self.send(prep, **send_kwargs) File "/usr/local/lib/python2.7/site-packages/requests/sessions.py", line 609, in send r = adapter.send(request, **kwargs) File "/usr/local/lib/python2.7/site-packages/requests/adapters.py", line 497, in send raise SSLError(e, request=request) requests.exceptions.SSLError: ("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",)
pitón3
Traceback (most recent call last): File "<string>", line 1, in <module> File "/usr/local/bin/python3.5/site-packages/requests/api.py", line 70, in get return request('get', url, params=params, **kwargs) File "/usr/local/bin/python3.5/site-packages/requests/api.py", line 56, in request return session.request(method=method, url=url, **kwargs) File "/usr/local/bin/python3.5/site-packages/requests/sessions.py", line 488, in request resp = self.send(prep, **send_kwargs) File "/usr/local/bin/python3.5/site-packages/requests/sessions.py", line 609, in send r = adapter.send(request, **kwargs) File "/usr/local/bin/python3.5/site-packages/requests/adapters.py", line 497, in send raise SSLError(e, request=request) requests.exceptions.SSLError: ("bad handshake: Error([('SSL routines', 'ssl3_get_server_certificate', 'certificate verify failed')],)",)
Desde https://stackoverflow.com/a/33717517/1695680
Para hacer que las solicitudes de python usen el paquete de certificados CA del sistema, se le debe indicar que lo use sobre su propio paquete incrustado
export REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt
Las solicitudes incorporan sus paquetes aquí, como referencia:
/usr/local/lib/python2.7/site-packages/requests/cacert.pem /usr/lib/python3/dist-packages/requests/cacert.pem
O en versiones más nuevas, use un paquete adicional para obtener certificados de: https://github.com/certifi/python-certifi
Para verificar desde qué archivo se cargan los certificados, puede probar:
Python 3.8.5 (default, Jul 28 2020, 12:59:40) >>> import certifi >>> certifi.where() '/etc/ssl/certs/ca-certificates.crt'
Luché con esto durante una semana más o menos recientemente. Finalmente encontré la forma de verificar un certificado autofirmado o firmado de forma privada en Python. Debe crear su propio archivo de paquete de certificados. No es necesario actualizar paquetes de certificados oscuros cada vez que actualiza una biblioteca, ni agregar nada al almacén de certificados del sistema.
Comience ejecutando el comando openssl que ejecutó antes, pero agregue -showcerts. openssl s_client -connect mysite.local:443 -showcerts
Esto le dará una salida larga y en la parte superior verá la cadena de certificados completa. Por lo general, esto significa tres certificados, el certificado del sitio web, el certificado intermedio y el certificado raíz en ese orden. Necesitamos colocar solo los certificados raíz e intermedios en un archivo siguiente en el orden opuesto.
Copie el último certificado, el certificado raíz, en un nuevo archivo de texto. Tome solo las cosas entre, e incluyendo:
-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----
Copie el certificado intermedio (también conocido como el certificado intermedio) en el nuevo archivo de texto bajo el certificado raíz. Nuevamente, tome las líneas Begin y End Certificate y todo lo demás.
Guarde este archivo de texto en el directorio donde reside su secuencia de comandos de Python. Mi recomendación es llamarlo CertBundle.pem
. (Si le asigna un nombre diferente o lo coloca en otro lugar de la estructura de carpetas, asegúrese de que la línea de verificación lo refleje). Actualice su secuencia de comandos para hacer referencia al nuevo paquete de certificados:
response = requests.post("https://www.example.com/", headers=headerContents, json=bodyContents, verify="CertBundle.pem")
Y eso es. Si solo tiene el certificado raíz o solo el intermedio, Python no puede validar toda la cadena de certificados. Pero, si incluye ambos certificados en el paquete de certificados que creó, entonces Python puede validar que el intermedio fue firmado por la raíz, y luego, cuando accede al sitio web, puede validar que el certificado del sitio web fue firmado por el certificado intermedio. .
editar: se corrigió la extensión de archivo para el paquete de certificados. Además, corrigió un par de errores gramaticales.
Mis dos centavos:
Gracias a esta otra respuesta , que me hizo verificar el código de las solicitudes reales, descubrí que no tiene que usar la variable env, pero puede configurar el parámetro "verificar" en su solicitud:
requests.get("https://whatever", verify="/my/path/to/cacert.crt", ...)
También está documentado , aunque solo pude encontrar la documentación después de haber hecho el descubrimiento (y el proyecto pypi apunta a un enlace muerto para doc) :D