Richieste Python che lanciano SSLError


349

Sto lavorando a un semplice script che coinvolge CAS, controllo di sicurezza jspring, reindirizzamento, ecc. Vorrei usare le richieste di Python di Kenneth Reitz perché è un ottimo lavoro! Tuttavia, CAS richiede di essere convalidato tramite SSL, quindi devo prima superare questo passaggio. Non so quali siano le richieste di Python? Dove dovrebbe risiedere questo certificato 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

Puoi condividere più informazioni sul codice? Sembra che ci sia un passaggio mancante.
TankorSmash

5
Dovresti sempre menzionare le versioni del software di cui hai bisogno di aiuto.
Piotr Dobrogost,

Ho riscontrato questo problema in cui utilizzo Python 3.5 Tornado 4.4. HTTPRequest imposta validate_cert = True, quindi puoi impostarlo su False per
gestirlo

Prova questo: request.get (' esempio.com ', verifica = certifi.where ())
Nei

Risposte:


460

Il problema riscontrato è causato da un certificato SSL non attendibile.

Come @dirk menzionato in un commento precedente, la soluzione più rapida è l'impostazione verify=False:

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

Si noti che ciò provocherà la mancata verifica del certificato. Ciò esporrà la tua applicazione a rischi per la sicurezza, come attacchi man-in-the-middle.

Naturalmente, applica il giudizio. Come menzionato nei commenti, questo può essere accettabile per applicazioni / script rapidi / usa e getta, ma in realtà non dovrebbe andare al software di produzione .

Se il solo controllo del certificato non è accettabile in un determinato contesto, considerare le seguenti opzioni, l'opzione migliore è impostare il verifyparametro su una stringa che è il percorso del.pem file del certificato (che dovresti ottenere con una sorta di sicurezza si intende).

Quindi, a partire dalla versione 2.0, il verifyparametro accetta i seguenti valori, con le rispettive semantiche:

  • True: causa la convalida del certificato rispetto alle autorità di certificazione attendibili della libreria (Nota: è possibile vedere quali richieste di certificati di root utilizzano tramite la libreria Certifi, un database di fiducia di RC estratto da Requests: Certifi - Trust Database for Humans ).
  • False: ignora completamente la convalida del certificato .
  • Percorso di un file CA_BUNDLE da utilizzare per le richieste per convalidare i certificati.

Fonte: Richieste - Verifica certificati SSL

Dai anche un'occhiata al certparametro sullo stesso link.


1
Sì, quando ho usato dotCloud in Ubuntu, è uscito lo stesso "certificato verificato non riuscito". Dopo aver modificato "request.session (headers = headers, hooks = hooks, verifica = False)" in "/usr/local/lib/python2.6/dist-packages/dotcloud/client/client.py", ha funzionato.
Diyismo,

2
Questo non è contrassegnato come corretto, ma posso verificare che funzioni (al contrario delle risposte di seguito).
khalid13,

40
@ khalid13: un'ascia "funziona" come medicinale per il mal di testa (niente testa, niente mal di testa). Non significa che sia una buona idea usarlo in questo modo. verify=Falsedisabilita il controllo del certificato SSL dell'host.
jfs,

24
@JFSebastian Onestamente, dipende da cosa stai facendo. Per la mia applicazione rapida / usa e getta, era più che sufficiente.
khalid13,

5
@diyism che rende tale cambiamento sembra molto pericoloso ...
binki

111

Da richiesta documentazione sulla verifica SSL :

Le richieste possono verificare i certificati SSL per le richieste HTTPS, proprio come un browser web. Per verificare il certificato SSL di un host, è possibile utilizzare l'argomento di verifica:

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

Se non vuoi verificare il tuo certificato SSL, crea verify=False


4
Bene, ho aggiunto la verifica = True, ma ho ancora ricevuto lo stesso errore esatto. Nessun cambiamento. Qualcos'altro deve essere richiesto, ma non so cosa potrebbe essere.
TedBurrows,

Suppongo che ora sia disceso nella follia SSL. Ho aggiunto questo al mio get iniziale get ... get (url1, headers = headers, cert = '/ etc / pki / tls / cert.pem', verifica = True, config = my_config) Quindi, ora ricevo questo errore. request.exceptions.SSLError: [Errno 336265225] _ssl.c: 351: errore: 140B0009: routine SSL: SSL_CTX_use_PrivateKey_file: PEM lib Non ho idea di cosa significhi.
TedBurrows,

14
Basta impostare verifica = Falso se non si desidera convalidare il certificato, ma se si dispone di un certificato autofirmato
Dirk,

16
Se hai un certificato autofirmato, scaricalo e imposta verifica sul suo nome file. Non ci sono scuse per impostare verifichi = Falso. verifica = '/ path / to / cert.pem'
Matthias Urlichs

14
Mi dispiace Boud, ho dovuto votare in basso questa risposta poiché le richieste non gestiscono le richieste HTTPS "come un browser web". Se la catena di affidabilità SSL completa (inclusi i certificati intermedi) non viene dichiarata su un server e richiede un ulteriore download del certificato, si riceverà l'errore di verifica SSL sopra riportato. I browser Web eseguiranno il download aggiuntivo e non contrassegneranno eventuali errori di certificato. Questo è un modo in cui un browser Web e le richieste differiscono. Ce ne sono altri Le richieste eseguono una verifica, ma non è buono come un browser.
Louis Cremen,

53

Il nome del file CA da utilizzare potrebbe passare tramite verify:

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

Se si utilizza verify=Truepoi requestsusa una propria serie di CA che potrebbero non avere CA che ha firmato il certificato del server.


12
@ 9emE0iL18gxCqLT: perché pensi che tutti i sistemi utilizzino il percorso che hai fornito? requestspuò essere impacchettato per la tua distribuzione. Corri python -mrequests.certsper scoprire dove punta.
jfs,

3
Se il bundle cacert della richiesta Python non è aggiornato, come posso aggiornarlo?
CMCDragonkai,

5
Non dovresti usarlo cacert.pemdal ricciolo. Contiene molti certificati revocati. Dai un'occhiata a Certifi (che utilizza Requests): certifi.io
Kenneth Reitz

3
@KennethReitz: 1- quali richieste utilizza non riesce per OP (altrimenti non c'era la domanda) 2- cacert.pemsono i certificati CA estratti da Mozilla (da cURL) - è solo un esempio (se l'elenco CA utilizzato da un web popolare -browser non può essere usato come esempio, quindi non so cosa possa essere) - il punto della risposta è che puoi passare il tuo file CA se l'elenco predefinito fallisce.
jfs,

Puoi farlo e utilizzare i certificati client contemporaneamente? Sto avendo problemi con questo.
user1156544

42

$ pip install -U requests[security]

  • Testato su Python 2.7.6 @ Ubuntu 14.04.4 LTS
  • Testato su Python 2.7.5 @ MacOSX 10.9.5 (Mavericks)

Quando questa domanda è stata aperta (2012-05), la versione delle Richieste era 0.13.1. Nella versione 2.4.1 (2014-09) sono stati introdotti gli extra di "sicurezza", usandocertifi pacchetto se disponibile.

In questo momento (2016-09) la versione principale è 2.11.1, che funziona bene senza verify=False . Non è necessario utilizzarlo requests.get(url, verify=False), se installato con requests[security]extra.


7
riparato pip install -U requests[security] --no-cachedue volte epip install certifi==2015.04.28
Aamir Abro il

@alanjds E se volessi configurare Python in modo che si fidasse di qualche certificato SSL o disabilitare la verifica del certificato ma a livello globale nell'ambiente, senza modificare il codice sorgente? Ad esempio, se scarico utilità Python esistenti (ad es. L'interfaccia della riga di comando di AWS) e desidero fidarmi dei certificati o ignorare la convalida del certificato per tali strumenti?
Howiecamp,

@Howiecamp allora si può andare risposta via JF-sebastian, immagino: stackoverflow.com/a/12865159/798575
alanjds

@alanjds Ma la sua risposta non presuppone che stia scrivendo il codice e / o abbia accesso al codice? Sto cercando di implementarlo a livello ambientale.
Howiecamp,

3
fare pip install --upgrade pipprima di installare il pacchetto di sicurezza delle richieste per evitare altri errori
Vincent Claes,

40

Ho riscontrato lo stesso problema e il certificato SSL verifica il problema non riuscito durante l'utilizzo di aws boto3, esaminando il codice boto3, ho riscontrato che REQUESTS_CA_BUNDLEnon è stato impostato, quindi ho risolto entrambi i problemi impostandolo 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')

Per aws-cli, suppongo che l'impostazione REQUESTS_CA_BUNDLE ~/.bashrcrisolverà questo problema (non testato perché il mio aws-cli funziona senza di esso).

REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt # ca-bundle.crt
export REQUESTS_CA_BUNDLE

2
Questo ha risolto il mio problema! Stavo usando Charles Proxy su Mac per eseguire il debug di una libreria che effettuava chiamate JSON alle API HTTPS. Ho installato il certificato Charless come specificato, l'ho aggiunto al portachiavi, ma Python ha continuato a fallire con: SSLError: ("handshake errato: errore ([('' Routine SSL ',' ssl3_get_server_certificate ',' certificato verifica fallito ')],)" ,) Per risolvere questo problema, ho finito per seguire i tuoi consigli sull'aggiunta di REQUESTS_CA_BUNDLE e sull'esportazione del certificato Charles dal mio portachiavi come file .pem. Ora funziona!
mallyvai,

Grazie, lo stesso problema era con Fiddler aperto
user565447

@ user565447 Sto provando a farlo funzionare con Fiddler in questo momento. L'impostazione di REQUESTS_CA_BUNDLE su Cidd di Fiddler dovrebbe funzionare?
Howiecamp,

19

Nel caso in cui tu abbia una libreria su cui fare affidamento requestse non puoi modificare il percorso di verifica (come con pyvmomi), dovrai trovare il cacert.pembundle con le richieste e aggiungere lì la tua CA. Ecco un approccio generico per trovare la cacert.pemposizione:

finestre

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

btw. @ request-devs, raggruppare i tuoi dolci con la richiesta è davvero, davvero fastidioso ... soprattutto il fatto che tu non sembri usare prima il sistema e questo non è documentato da nessuna parte.

aggiornare

in situazioni in cui stai utilizzando una libreria e non hai alcun controllo sulla posizione del bundle ca, puoi anche impostare esplicitamente la posizione del bundle ca come bundle ca a livello di host:

REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-bundle.crt python -c "import requests; requests.get('https://somesite.com';)"

Cento volte: l'incapacità della chiave di modificare il verifypercorso.
ghukill,

Cosa succede se si utilizza un certificato autofirmato? Quale sarebbe la CA in quel caso?
user1114

Piccolo aggiornamento - per Python 3.6, ci dovrebbero essere parentesi per il comando print - python -c "richieste di importazione; print (
request.certs.where

15

Devo affrontare lo stesso problema usando gspread e questi comandi funzionano per me:

sudo pip uninstall -y certifi
sudo pip install certifi==2015.04.28

Questo è stato per me. Grazie :)
alex-mcleod,

4
Questo ha il rovescio della medaglia di reinstallare certificati potenzialmente revocati / non attendibili dalla versione precedente di certifi, NON raccomandato.
dragon788,

se per qualche motivo sei costretto a rimanere con una versione precedente di Python 2.7, il downgrade del certifi è l'unico approccio che ha funzionato per me
sean

15

Se si desidera rimuovere gli avvisi, utilizzare il codice seguente.

import urllib3

urllib3.disable_warnings()

e verify=Falsecon request.geto postmetodo


12

Ho trovato un approccio specifico per risolvere un problema simile. L'idea punta al file cacert archiviato nel sistema e utilizzato da altre applicazioni basate su SSL.

In Debian (non sono sicuro che sia lo stesso in altre distribuzioni) i file del certificato (.pem) sono archiviati in /etc/ssl/certs/Quindi, questo è il codice che funziona per me:

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

Per indovinare quale pemfile scegliere, ho cercato l'URL e ho verificato quale Autorità di certificazione (CA) ha generato il certificato.

MODIFICA: se non riesci a modificare il codice (perché stai eseguendo una terza app) puoi provare ad aggiungere pemdirettamente il certificato /usr/local/lib/python2.7/dist-packages/requests/cacert.pem(es. Copiandolo alla fine del file).


2
Post correlati per il debug di CA_BUNDLE utilizzato da Python.
chk,

Che ne dici di sostituire /usr/local/lib/python2.7/dist-packages/requests/cacert.pemcon un link simbolico all'archivio del sistema operativo?
CMCDragonkai,

8

Se non ti preoccupi del certificato basta usare verify=False.

import requests

url = "Write your url here"

returnResponse = requests.get(url, verify=False)

7

Dopo ore di debug sono riuscito a farlo funzionare solo con i seguenti pacchetti:

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

utilizzando OpenSSL 1.0.2g 1 Mar 2016

Senza questi pacchetti verify=Falsenon funzionava.

Spero che questo aiuti qualcuno.


5

Ho riscontrato lo stesso problema. Risulta che non ho installato il certificato intermedio sul mio server (basta aggiungerlo alla fine del certificato come mostrato di seguito).

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

Assicurati di avere installato il pacchetto ca-certificati:

sudo apt-get install ca-certificates

L'aggiornamento dell'ora può anche risolvere questo:

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

Se stai usando un certificato autofirmato, probabilmente dovrai aggiungerlo manualmente al tuo sistema.


Nota, questo si applica solo alle installazioni di richieste tramite apt-get, che viene modificato da Debian / Ubuntu per usare i certificati di sistema. Richiede navi appropriate con un proprio pacchetto CA accuratamente curato: certifi.io
Kenneth Reitz

La CA principale non dovrebbe essere sufficiente? Perché hai bisogno degli intermedi?
timmy

5

Se le chiamate di richiesta vengono sepolte da qualche parte nel profondo del codice e non si desidera installare il certificato del server, quindi, solo a scopo di debug , è possibile effettuare richieste di 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!')

Non usare mai in produzione!


4

Troppo tardi alla festa immagino, ma volevo incollare la correzione per gli altri vagabondi come me! Quindi il seguente ha funzionato per me su Python 3.7.x

Digita quanto segue nel tuo terminale

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

Prova a eseguire di nuovo il tuo script / richieste e vedi se funziona (sono sicuro che non sarà ancora risolto!). Se non ha funzionato, prova a eseguire direttamente il seguente comando nel terminale

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

3

Ho combattuto questo problema per ORE.

Ho provato ad aggiornare le richieste. Quindi ho aggiornato certifi. Ho indicato verifica a certifi.where () (il codice lo fa comunque per impostazione predefinita). Niente ha funzionato.

Alla fine ho aggiornato la mia versione di Python a Python 2.7.11. Ero su Python 2.7.5 che aveva alcune incompatibilità con il modo in cui i certificati sono verificati. Una volta aggiornato Python (e una manciata di altre dipendenze) ha iniziato a funzionare.


Se hai aggiornato OpenSSL a una versione> 1.0.1, probabilmente quello era il problema. Vedi la mia risposta qui sotto. stackoverflow.com/a/44543047/1413201
Tim Ludwinski

Il passaggio da Python 2.7.9 a 2.7.10 ha risolto questo problema per me.
crazystick,

3

Questo è simile alla risposta di @ rafael-almeida, ma voglio sottolineare che a partire dalle richieste 2.11+, non ci sono 3 valori che verifypossono assumere, in realtà ce ne sono 4:

  • True: convalida rispetto alle CA attendibili interne delle richieste.
  • False: ignora completamente la convalida del certificato . (Non consigliato)
  • Percorso di un file CA_BUNDLE. le richieste lo useranno per convalidare i certificati del server.
  • Percorso di una directory contenente file di certificati pubblici. le richieste lo useranno per convalidare i certificati del server.

Il resto della mia risposta riguarda il n. 4, come utilizzare una directory contenente certificati per convalidare:

Ottieni i certificati pubblici necessari e inseriscili in una directory.

A rigor di termini, probabilmente "dovresti" usare un metodo fuori banda per ottenere i certificati, ma puoi anche scaricarli usando qualsiasi browser.

Se il server utilizza una catena di certificati, assicurarsi di ottenere ogni singolo certificato nella catena.

Secondo la documentazione delle richieste, la directory contenente i certificati deve essere prima elaborata con l'utilità "rehash" ( openssl rehash).

(Ciò richiede openssl 1.1.1+ e non tutte le implementazioni di Windows openssl supportano rehash. Se openssl rehashnon funziona, puoi provare a eseguire lo script rehash ruby ​​su https://github.com/ruby/openssl/blob/master /sample/c_rehash.rb , anche se non l'ho provato.)

Ho avuto qualche problema ad ottenere richieste per riconoscere i miei certificati, ma dopo aver usato il openssl x509 -outform PEMcomando per convertire i certificati in Base64.pem formato , tutto ha funzionato perfettamente.

Puoi anche semplicemente fare il rehashing pigro:

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")

2

Esiste attualmente un problema nel modulo delle richieste che causa questo errore, presente nella v2.6.2 alla v2.12.4 (ATOW): https://github.com/kennethreitz/requests/issues/2573

La soluzione alternativa a questo problema è l'aggiunta della seguente riga: 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'


FWIW, è ancora presente con richieste == 2.13.0. La soluzione precedente sopra risolve ancora.
Tamás Szelei,

1

Come menzionato da @Rafael Almeida, il problema riscontrato è causato da un certificato SSL non attendibile. Nel mio caso, il certificato SSL non era attendibile dal mio server. Per aggirare il problema senza compromettere la sicurezza, ho scaricato il certificato e l'ho installato sul server (semplicemente facendo doppio clic sul file .crt e quindi Installa certificato ...).


0

Non è possibile aggiungere opzioni se le richieste vengono chiamate da un altro pacchetto. In tal caso l'aggiunta di certificati al pacchetto cacert è il percorso diretto, ad esempio ho dovuto aggiungere "CA Server intermedio primario Classe 1 StartCom", per la quale ho scaricato il certificato root in StartComClass1.pem. dato che virtualenv si chiama caldav, ho aggiunto il certificato 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 di questi potrebbe essere sufficiente, non ho controllato


0

Avevo un problema di convalida della certificazione simile o uguale. Ho letto che le versioni di OpenSSL precedenti alla 1.0.2, le cui richieste dipendono a volte hanno problemi a convalidare certificati forti (vedi qui ). CentOS 7 sembra usare 1.0.1e che sembra avere il problema.

Non ero sicuro di come risolvere questo problema su CentOS, quindi ho deciso di consentire certificati CA a 1024 bit più deboli.

import certifi # This should be already installed as a dependency of 'requests'
requests.get("https://example.com", verify=certifi.old_where())

Uso un Python 2.7.10 installato da ArcGIS e non è installato alcun modulo certifi. Il modulo di richiesta installato è nella versione 2.11.1.
Lucas,

0

Ho dovuto eseguire l'aggiornamento da Python 3.4.0 a 3.4.6

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

0

Nel mio caso il motivo era abbastanza banale.

Avevo saputo che la verifica SSL aveva funzionato fino a pochi giorni prima e funzionava infatti su una macchina diversa.

Il mio passo successivo è stato quello di confrontare il contenuto e le dimensioni del certificato tra la macchina su cui stava funzionando la verifica e quella su cui non lo era.

Ciò mi ha portato rapidamente a determinare che il Certificato sulla macchina funzionante "in modo errato" non era buono, e una volta sostituito con il certificato "buono", tutto andava bene.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.