Solicitudes de Python lanzando SSLError

349

Estoy trabajando en un script simple que involucra CAS, verificación de seguridad de jspring, redirección, etc. ¡Me gustaría usar las solicitudes de Python de Kenneth Reitz porque es un gran trabajo! Sin embargo, CAS requiere ser validado a través de SSL, así que primero tengo que pasar ese paso. No sé lo que quiere Python. ¿Dónde se supone que reside este certificado SSL?

Traceback (most recent call last):
  File "./test.py", line 24, in <module>
  response = requests.get(url1, headers=headers)
  File "build/bdist.linux-x86_64/egg/requests/api.py", line 52, in get
  File "build/bdist.linux-x86_64/egg/requests/api.py", line 40, in request
  File "build/bdist.linux-x86_64/egg/requests/sessions.py", line 209, in request 
  File "build/bdist.linux-x86_64/egg/requests/models.py", line 624, in send
  File "build/bdist.linux-x86_64/egg/requests/models.py", line 300, in _build_response
  File "build/bdist.linux-x86_64/egg/requests/models.py", line 611, in send
requests.exceptions.SSLError: [Errno 1] _ssl.c:503: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
TedBurrows
fuente
¿Puedes compartir más información del código? Parece que falta un paso.
TankorSmash
55
Siempre debe mencionar las versiones de software con las que necesita ayuda.
Piotr Dobrogost
Tengo este problema cuando uso python 3.5 tornado 4.4. HTTPRequest establece validate_cert = True, por lo que puede configurarlo False para tratarlo
pan7an
Pruebe esto: request.get (' example.com ', verificar = certifi.where ())
Nei hace

Respuestas:

460

El problema que tiene es causado por un certificado SSL no confiable.

Como @dirk mencionó en un comentario anterior, la solución más rápida es la configuración verify=False:

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

Tenga en cuenta que esto hará que el certificado no se verifique. Esto expondrá su aplicación a riesgos de seguridad, como ataques de hombre en el medio.

Por supuesto, aplique el juicio. Como se menciona en los comentarios, esto puede ser aceptable para aplicaciones / scripts rápidos / descartables, pero realmente no debería ir al software de producción .

Si simplemente omitir la verificación del certificado no es aceptable en su contexto particular, considere las siguientes opciones, su mejor opción es establecer el verifyparámetro en una cadena que sea la ruta del .pemarchivo del certificado (que debe obtener mediante algún tipo de seguridad medio).

Entonces, a partir de la versión 2.0, el verifyparámetro acepta los siguientes valores, con su semántica respectiva:

  • True: hace que el certificado se valide contra las autoridades de certificación de confianza de la propia biblioteca (Nota: puede ver qué Solicitudes de certificados raíz utiliza a través de la biblioteca Certifi, una base de datos de confianza de RC extraídos de Solicitudes: Certifi - Base de datos de confianza para humanos ).
  • False: evita la validación del certificado por completo .
  • Ruta a un archivo CA_BUNDLE para que las Solicitudes las usen para validar los certificados.

Fuente: Solicitudes - Verificación del certificado SSL

También eche un vistazo al certparámetro en el mismo enlace.

Rafael Almeida
fuente
1
Sí, cuando usé dotCloud en ubuntu, salió el mismo "certificado fallido". Después de modificado "request.session (encabezados = encabezados, ganchos = ganchos, verificar = Falso)" en "/usr/local/lib/python2.6/dist-packages/dotcloud/client/client.py", funcionó.
diyism
2
Esto no está marcado como correcto, pero puedo verificar que funcione (a diferencia de las respuestas a continuación).
khalid13
40
@ khalid13: Un hacha "funciona" como medicamento para el dolor de cabeza (sin cabeza, sin dolor de cabeza). No significa que sea una buena idea usarlo de esa manera. verify=Falsedeshabilita la comprobación del certificado SSL del host.
jfs
24
@JFSebastian Honestamente, depende de lo que estés haciendo. Para mi aplicación rápida / desechable, fue más que suficiente.
khalid13
55
@diyism hacer un cambio de sonidos tales muy inseguros ...
binki
111

De la documentación de solicitudes de verificación SSL :

Las solicitudes pueden verificar certificados SSL para solicitudes HTTPS, al igual que un navegador web. Para verificar el certificado SSL de un host, puede usar el argumento de verificación:

>>> requests.get('https://kennethreitz.com', verify=True)

Si no desea verificar su certificado SSL, haga verify=False

Boud
fuente
44
Bueno, agregué elify = True, pero aún recibí exactamente el mismo error. Ningún cambio. Se debe requerir algo más, pero no sé qué podría ser.
TedBurrows
Supongo que ahora he descendido a la locura SSL. Agregué esto a mi get inicial ... get (url1, headers = headers, cert = '/ etc / pki / tls / cert.pem', verificar = True, config = my_config) Entonces, ahora recibo este error. request.exceptions.SSLError: [Errno 336265225] _ssl.c: 351: error: 140B0009: Rutinas SSL: SSL_CTX_use_PrivateKey_file: PEM lib No tengo ni idea de lo que esto significa.
TedBurrows
14
Simplemente configure verifique = Falso si no desea validar el certificado, ahora si tiene un certificado autofirmado
Dirk
16
Si tiene un certificado autofirmado, descárguelo y configure verificar en su nombre de archivo. No hay excusa alguna para establecer verificar = Falso. verificar = '/ ruta / a / cert.pem'
Matthias Urlichs
14
Lo siento, Boud, necesitaba rechazar esta respuesta, ya que las solicitudes no manejan las solicitudes HTTPS "como un navegador web". Si la cadena de confianza SSL completa (incluidos los certificados intermedios) no se declara en un servidor y requiere una descarga de certificado adicional, recibirá el error de verificación SSL anterior. Los navegadores web realizarán la descarga adicional y no marcarán ningún error de certificado. Esta es una forma en que un navegador web y solicitudes difieren. Hay otros. Requests realiza algunas verificaciones, pero no es tan bueno como un navegador.
Louis Cremen
53

El nombre del archivo de CA para usar puede pasar por verify:

cafile = 'cacert.pem' # http://curl.haxx.se/ca/cacert.pem
r = requests.get(url, verify=cafile)

Si lo usa, verify=Trueentonces requestsusa su propio conjunto de CA que podría no tener CA que firmó su certificado de servidor.

jfs
fuente
12
@ 9emE0iL18gxCqLT: ¿por qué cree que todos los sistemas utilizan la ruta que proporcionó? requestsSe puede empaquetar para su distribución. Corre python -mrequests.certspara averiguar a dónde apunta.
jfs
3
Si el paquete cacert de la solicitud de Python no está actualizado, ¿cómo lo actualizo?
CMCDragonkai
55
No deberías usar eso cacert.pemde curl. Contiene muchos certificados revocados. Echa un vistazo a Certifi (que Solicitudes usa): certifi.io
Kenneth Reitz
3
@KennethReitz: 1- lo que utiliza Requests falla para OP (de lo contrario no había la pregunta) 2- cacert.pemson los certificados de CA extraídos de Mozilla (por cURL) - es solo un ejemplo (si la lista de CA utilizada por una web popular -Browser no se puede usar como ejemplo, entonces no sé qué puede ser): el punto de la respuesta es que puede pasar su propio archivo CA si falla la lista predeterminada.
jfs
¿Puedes hacer esto y usar certificados de cliente al mismo tiempo? Tengo problemas con esto.
user1156544
42

$ pip install -U requests[security]

  • Probado en Python 2.7.6 @ Ubuntu 14.04.4 LTS
  • Probado en Python 2.7.5 @ MacOSX 10.9.5 (Mavericks)

Cuando se abrió esta pregunta (2012-05), la versión de Solicitudes era 0.13.1. En la versión 2.4.1 (2014-09) se introdujeron los extras de "seguridad", utilizando el certifipaquete si está disponible.

En este momento (2016-09) la versión principal es 2.11.1, que funciona bien sin ella verify=False . No es necesario usar requests.get(url, verify=False), si está instalado con requests[security]extras.

alanjds
fuente
77
arreglado por pip install -U requests[security] --no-cachedos veces ypip install certifi==2015.04.28
Aamir Abro
@alanjds ¿Qué sucede si deseo configurar Python para confiar en algún certificado SSL o deshabilitar la verificación del certificado pero globalmente en el entorno, sin editar el código fuente? Por ejemplo, si descargo las utilidades de Python existentes (por ejemplo, la AWS CLI) y deseo confiar en los certificados o ignorar la validación de certificados para esas herramientas.
Howiecamp
@Howiecamp, entonces puedes ir a través de la respuesta jf-sebastian, supongo: stackoverflow.com/a/12865159/798575
alanjds
@alanjds ¿Pero su respuesta no asume que estoy escribiendo el código y / o tengo acceso al código? Estoy buscando implementar esto a nivel ambiental.
Howiecamp
3
hacer pip install --upgrade pipantes de instalar el paquete de seguridad de solicitudes para evitar otros errores
Vincent Claes
40

Encontré el mismo problema y el certificado SSL verificó un problema fallido al usar aws boto3, al revisar el código boto3, descubrí REQUESTS_CA_BUNDLEque no está configurado, así que solucioné ambos problemas configurándolo manualmente:

from boto3.session import Session
import os

# debian
os.environ['REQUESTS_CA_BUNDLE'] = os.path.join(
    '/etc/ssl/certs/',
    'ca-certificates.crt')
# centos
#   'ca-bundle.crt')

Para aws-cli, supongo que configurar REQUESTS_CA_BUNDLE ~/.bashrcsolucionará este problema (no probado porque mi aws-cli funciona sin él).

REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt # ca-bundle.crt
export REQUESTS_CA_BUNDLE
Yong
fuente
2
Esto solucionó mi problema! Estaba usando Charles Proxy en Mac para depurar una biblioteca que hacía llamadas JSON a las API HTTPS. Instalé el certificado Charless como se especificó, lo agregué al llavero, pero Python siguió fallando con: SSLError: ("mal apretón de manos: Error ([('' rutinas SSL ',' ssl3_get_server_certificate ',' verificar certificado falló ')],)" ,) Para solucionar esto, terminé siguiendo su consejo sobre agregar REQUESTS_CA_BUNDLE y exportar el certificado de Charles de mi llavero como un archivo .pem. ¡Ahora funciona!
mallyvai
Gracias, el mismo problema fue con Fiddler abierto
usuario565447
@ user565447 Estoy tratando de que esto funcione con Fiddler en este momento. ¿Debería establecer REQUESTS_CA_BUNDLE en el certificado de Fiddler?
Howiecamp
19

En caso de que tenga una biblioteca que se base requestsy no pueda modificar la ruta de verificación (como con pyvmomi), entonces tendrá que encontrar las cacert.pemsolicitudes agrupadas y agregar su CA allí. Aquí hay un enfoque genérico para encontrar la cacert.pemubicación:

ventanas

C:\>python -c "import requests; print requests.certs.where()"
c:\Python27\lib\site-packages\requests-2.8.1-py2.7.egg\requests\cacert.pem

linux

#  (py2.7.5,requests 2.7.0, verify not enforced)
root@host:~/# python -c "import requests; print requests.certs.where()"
/usr/lib/python2.7/dist-packages/certifi/cacert.pem

#  (py2.7.10, verify enforced)
root@host:~/# python -c "import requests; print requests.certs.where()"
/usr/local/lib/python2.7/dist-packages/requests/cacert.pem

por cierto. @ request-devs, agrupar tus propias cacerts con request es realmente muy molesto ... especialmente el hecho de que no pareces usar el sistema ca store primero y esto no está documentado en ningún lado.

actualizar

en situaciones en las que está utilizando una biblioteca y no tiene control sobre la ubicación del paquete ca, también puede establecer explícitamente la ubicación del paquete ca para que sea el paquete ca de todo el host:

REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-bundle.crt python -c "import requests; requests.get('https://somesite.com';)"
tintin
fuente
Cien veces esto: la clave es la incapacidad para modificar la verifyruta.
ghukill
¿Qué pasa si está utilizando un certificado autofirmado? ¿Cuál sería la CA en ese caso?
usuario1114
Pequeña actualización: para python 3.6, debe haber paréntesis para el comando de impresión: python -c "solicitudes de importación; print (
request.certs.where
15

Tengo el mismo problema al usar gspread y estos comandos me funcionan:

sudo pip uninstall -y certifi
sudo pip install certifi==2015.04.28
usuario941581
fuente
Esto lo hizo por mí. Gracias :)
alex-mcleod
44
Esto tiene el inconveniente de reinstalar certificados potencialmente revocados / no confiables de la versión anterior de certifi, NO recomendado.
dragon788
Si por alguna razón se ve obligado a seguir con una versión anterior de Python 2.7, la degradación de certifi es el único enfoque que funcionó para mí
Seans
15

Si desea eliminar las advertencias, use el código a continuación.

import urllib3

urllib3.disable_warnings()

y verify=Falsecon request.geto postmétodo

AniketGole
fuente
12

He encontrado un enfoque específico para resolver un problema similar. La idea es señalar el archivo cacert almacenado en el sistema y utilizado por otras aplicaciones basadas en SSL.

En Debian (no estoy seguro si es igual en otras distribuciones) los archivos de certificado (.pem) se almacenan en /etc/ssl/certs/So, este es el código que funciona para mí:

import requests
verify='/etc/ssl/certs/cacert.org.pem'
response = requests.get('https://lists.cacert.org', verify=verify)

Para adivinar qué pemarchivo elegir, tengo que buscar la url y verificar qué Autoridad de certificación (CA) ha generado el certificado.

EDITAR: si no puede editar el código (porque está ejecutando una tercera aplicación), puede intentar agregar el pemcertificado directamente /usr/local/lib/python2.7/dist-packages/requests/cacert.pem(por ejemplo, copiarlo al final del archivo).

chk
fuente
2
Publicación relacionada para la depuración de CA_BUNDLE utilizada por python.
chk
¿Qué hay de reemplazar /usr/local/lib/python2.7/dist-packages/requests/cacert.pemcon un enlace simbólico a la tienda del sistema operativo?
CMCDragonkai
8

Si no te molesta el certificado, solo úsalo verify=False.

import requests

url = "Write your url here"

returnResponse = requests.get(url, verify=False)
Yogesh Prasad
fuente
7

Después de horas de depuración, solo pude hacer que esto funcione con los siguientes paquetes:

requests[security]==2.7.0  # not 2.18.1
cryptography==1.9  # not 2.0

utilizando OpenSSL 1.0.2g 1 Mar 2016

Sin estos paquetes verify=Falseno funcionaba.

Espero que esto ayude a alguien.

Miguel
fuente
5

Me encontré con el mismo problema. Resulta que no había instalado el certificado intermedio en mi servidor (solo añádalo al final de su certificado como se ve a continuación).

https://www.digicert.com/ssl-support/pem-ssl-creation.htm

Asegúrese de tener instalado el paquete de certificados de ca:

sudo apt-get install ca-certificates

Actualizar el tiempo también puede resolver esto:

sudo apt-get install ntpdate
sudo ntpdate -u ntp.ubuntu.com

Si está utilizando un certificado autofirmado, probablemente tendrá que agregarlo a su sistema manualmente.

Marius Craciunoiu
fuente
Tenga en cuenta que esto solo se aplica a las instalaciones de Solicitudes a través de apt-get, que es modificado por Debian / Ubuntu para usar certificados del sistema. Solicita envíos apropiados con su propio paquete CA cuidadosamente seleccionado: certifi.io
Kenneth Reitz
¿No debería ser suficiente la CA raíz? ¿Por qué necesitas los intermedios?
Timmy
5

Si las llamadas de solicitud están enterradas en algún lugar profundo del código y no desea instalar el certificado del servidor, entonces, solo con fines de depuración , es posible realizar solicitudes de monkeypatch:

import requests.api
import warnings


def requestspatch(method, url, **kwargs):
    kwargs['verify'] = False
    return _origcall(method, url, **kwargs)

_origcall = requests.api.request
requests.api.request = requestspatch
warnings.warn('Patched requests: SSL verification disabled!')

¡Nunca lo use en producción!

xmedeko
fuente
4

Supongo que fue demasiado tarde para la fiesta, ¡pero quería pegar la solución para otros vagabundos como yo! Así que lo siguiente funcionó para mí en Python 3.7.x

Escriba lo siguiente en su terminal

pip install --upgrade certifi      # hold your breath..

Intente ejecutar su script / solicitudes nuevamente y vea si funciona (¡estoy seguro de que aún no se solucionará!). Si no funcionó, intente ejecutar el siguiente comando en la terminal directamente

open /Applications/Python\ 3.6/Install\ Certificates.command  # please replace 3.6 here with your suitable python version
codificador d
fuente
3

Luché contra este problema por HORAS.

Traté de actualizar las solicitudes. Luego actualicé certifi. Apunté verificar a certifi.where () (el código hace esto de manera predeterminada de todos modos). Nada funcionó.

Finalmente actualicé mi versión de python a python 2.7.11. Estaba en Python 2.7.5 que tenía algunas incompatibilidades con la forma en que se verifican los certificados. Una vez que actualicé Python (y un puñado de otras dependencias) comenzó a funcionar.

ajon
fuente
Si actualizó OpenSSL a una versión> 1.0.1, probablemente ese era el problema. Mira mi respuesta a continuación. stackoverflow.com/a/44543047/1413201
Tim Ludwinski
Pasar de Python 2.7.9 a 2.7.10 me arregló esto.
crazystick
3

Esto es similar a la respuesta de @ rafael-almeida, pero quiero señalar que a partir de las solicitudes 2.11+, no hay 3 valores que verifypuedan tomar, en realidad hay 4:

  • True: valida contra las CA de confianza internas de las solicitudes.
  • False: evita la validación del certificado por completo . (No recomendado)
  • Ruta a un archivo CA_BUNDLE. las solicitudes usarán esto para validar los certificados del servidor.
  • Ruta a un directorio que contiene archivos de certificados públicos. las solicitudes usarán esto para validar los certificados del servidor.

El resto de mi respuesta es sobre el n. ° 4, cómo usar un directorio que contiene certificados para validar:

Obtenga los certificados públicos necesarios y colóquelos en un directorio.

Estrictamente hablando, probablemente "debería" usar un método fuera de banda para obtener los certificados, pero también puede descargarlos usando cualquier navegador.

Si el servidor usa una cadena de certificados, asegúrese de obtener todos los certificados de la cadena.

De acuerdo con la documentación de las solicitudes, el directorio que contiene los certificados debe procesarse primero con la utilidad "rehash" ( openssl rehash).

(Esto requiere openssl 1.1.1+, y no todas las implementaciones de Windows openssl admiten rehash. Si openssl rehashno funciona para usted, puede intentar ejecutar el script rehash ruby ​​en https://github.com/ruby/openssl/blob/master /sample/c_rehash.rb , aunque no lo he intentado).

Tuve algunos problemas para obtener solicitudes para reconocer mis certificados, pero después de usar el openssl x509 -outform PEMcomando para convertir los certificados al .pemformato Base64 , todo funcionó a la perfección.

También puedes simplemente hacer una repetición perezosa:

try:
    # As long as the certificates in the certs directory are in the OS's certificate store, `verify=True` is fine.
    return requests.get(url, auth=auth, verify=True)
except requests.exceptions.SSLError:
    subprocess.run(f"openssl rehash -compat -v my_certs_dir", shell=True, check=True)
    return requests.get(url, auth=auth, verify="my_certs_dir")
cowlinator
fuente
2

Actualmente hay un problema en el módulo de solicitudes que causa este error, presente en v2.6.2 a v2.12.4 (ATOW): https://github.com/kennethreitz/requests/issues/2573

La solución para este problema es agregar la siguiente línea: requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS'

Peter
fuente
FWIW, todavía está presente con solicitudes == 2.13.0. La solución anterior lo arregla todavía.
Tamás Szelei
1

Como mencionó @Rafael Almeida, el problema que tiene es causado por un certificado SSL no confiable. En mi caso, el servidor no confiaba en el certificado SSL. Para solucionar esto sin comprometer la seguridad, descargué el certificado y lo instalé en el servidor (simplemente haciendo doble clic en el archivo .crt y luego Instalar certificado ...).

Miguel
fuente
0

No es factible agregar opciones si se solicitan solicitudes desde otro paquete. En ese caso, agregar certificados al paquete cacert es la ruta directa, por ejemplo, tuve que agregar "StartCom Class 1 Primary Intermediate Server CA", para lo cual descargué el certificado raíz en StartComClass1.pem. dado que mi virtualenv se llama caldav, agregué el certificado con:

cat StartComClass1.pem >> .virtualenvs/caldav/lib/python2.7/site-packages/pip/_vendor/requests/cacert.pem
cat temp/StartComClass1.pem >> .virtualenvs/caldav/lib/python2.7/site-packages/requests/cacert.pem

uno de esos podría ser suficiente, no verifiqué

rhoerbe
fuente
0

Estaba teniendo un problema de validación de certificación similar o similar. Leí que las versiones de OpenSSL inferiores a la 1.0.2, de las cuales depende la solicitud, a veces tienen problemas para validar certificados sólidos (ver aquí ). CentOS 7 parece usar 1.0.1e, que parece tener el problema.

No estaba seguro de cómo solucionar este problema en CentOS, así que decidí permitir certificados CA de 1024 bits más débiles.

import certifi # This should be already installed as a dependency of 'requests'
requests.get("https://example.com", verify=certifi.old_where())
Tim Ludwinski
fuente
Uso un Python 2.7.10 instalado por ArcGIS y no hay un módulo certifi instalado. El módulo de solicitudes instalado está en la versión 2.11.1.
Lucas
0

Tuve que actualizar de Python 3.4.0 a 3.4.6

pyenv virtualenv 3.4.6 myvenv
pyenv activate myvenv
pip install -r requirements.txt
Pablo
fuente
0

En mi caso, la razón fue bastante trivial.

Sabía que la verificación SSL había funcionado hasta unos días antes, y de hecho estaba trabajando en una máquina diferente.

El siguiente paso fue comparar el contenido y el tamaño del certificado entre la máquina en la que funcionaba la verificación y la que no.

Esto rápidamente me llevó a determinar que el Certificado en la máquina que funcionaba "incorrectamente" no era bueno, y una vez que lo reemplacé con el certificado "bueno", todo estuvo bien.

mastDrinkNimbuPani
fuente