HTTPS e SSL3_GET_SERVER_CERTIFICATE: verifica del certificato non riuscita, CA è OK


208

Sto usando XAMPP per lo sviluppo. Di recente ho aggiornato la mia installazione di xampp da una versione precedente alla 1.7.3.

Ora quando arriccia i siti abilitati HTTPS ottengo la seguente eccezione

Errore irreversibile: eccezione non rilevata 'RequestCore_Exception' con messaggio 'risorsa cURL: ID risorsa # 55; Errore cURL: problema con certificato SSL, verificare che il certificato CA sia OK. Dettagli: errore: 14090086: routine SSL: SSL3_GET_SERVER_CERTIFICATE: verifica certificato non riuscita (60) '

Tutti suggeriscono di utilizzare alcune opzioni di arricciatura specifiche dal codice PHP per risolvere questo problema. Penso che non dovrebbe essere così. Perché non ho avuto alcun problema con la mia vecchia versione di XAMPP ed è successo solo dopo aver installato la nuova versione.

Ho bisogno di aiuto per capire quali impostazioni cambiano nella mia installazione di PHP, Apache ecc. In grado di risolvere questo problema.

Risposte:


145

il ricciolo includeva un elenco di CA accettate, ma non raggruppava più QUALSIASI certificati CA. Quindi, per impostazione predefinita, rifiuterà tutti i certificati SSL come non verificabili.

Dovrai ottenere il certificato della CA e puntare il ricciolo verso di esso. Maggiori dettagli ai dettagli di cURLS sui certificati SSL del server .


4
Il ricciolo sta accadendo nella libreria php dei servizi web di Amazon. Non ho capito come risolverlo senza modificare il codice della libreria.
Josnidhin,

41
Quindi disattivare la verifica del certificato ( CURLOPT_SSL_VERIFYPEER-> false). O aggiungi il certificato CA del sito con cui stai tentando di eseguire SSL o disabiliti la verifica CA. Quelle sono le uniche due opzioni disponibili.
Marc B,

78
Semplicemente - impostazione CURLOPT_SSL_VERIFYPEERper falsesconfiggere lo scopo dell'utilizzo di SSL.
Fino

13
@Finché non sconfigge metà dello scopo di SSL? Ottieni ancora privacy tra te e il tuo pari: semplicemente non hai l'autenticità del tuo pari.
Mark Fox,

10
senza autenticità, che senso ha crittografare i dati che stai inviando? Se sei stato MITMed, i dati sono comunque compromessi
hdgarrood

290

È un problema abbastanza comune in Windows. Devi solo impostare cacert.pemsu curl.cainfo.

Da PHP 5.3.7 potresti fare:

  1. scarica https://curl.haxx.se/ca/cacert.pem e salvalo da qualche parte.
  2. update php.ini- aggiungi curl.cainfo = "PATH_TO / cacert.pem"

Altrimenti dovrai fare quanto segue per ogni risorsa cURL:

curl_setopt ($ch, CURLOPT_CAINFO, "PATH_TO/cacert.pem");

2
Questo ha funzionato per me in XAMPP su OS X. Ha risolto un problema in cui un plug-in di Wordpress non si aggiornava a causa dell'incapacità di individuare un certificato locale.
Jonathan Nicol,

8
Per chiunque cercasse di risolvere questo problema su Windows usando Apache, ho dovuto impostare il percorso completo (cioè C: \ PATH_TO \ cacert.pem) nel mio codice PHP. Su IIS, il percorso relativo sembrava funzionare correttamente.
http203,

Se cacert.pem si trova nella stessa directory, curl_setopt ($ ch, CURLOPT_CAINFO, dirname ( FILE ). '/Cacert.pem'); funzionerà
mujaffars l'

7
Quando si utilizza WampServer con 2., è necessario aggiungere la variabile a due php.inifile separati . Vedi stackoverflow.com/a/25706713/1101095
Nate

La cosa sconcertante / ironica è che puoi scaricare curl.haxx.se/ca/cacert.pem su HTTPS senza specificare alcuna opzione aggiuntiva. Il certificato per curl.haxx.se è supportato nel curl stesso?
qbolec,

84

Attenzione: questo può introdurre problemi di sicurezza contro cui SSL è progettato per proteggere, rendendo insicuro l'intero codice. Va contro ogni pratica raccomandata.

Ma una soluzione davvero semplice che ha funzionato per me è stata quella di chiamare:

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

prima di chiamare:

curl_exec():

nel file php.

Credo che ciò disabiliti tutta la verifica dei certificati SSL.


65
... e disabilitando la verifica dei certificati, si lascia aperta la porta a potenziali attacchi MITM, che SSL / TLS altrimenti mira a proteggere. NON FARE QUESTO!
Bruno,

12
Sì. Avrei dovuto attirare maggiormente l'attenzione su questo nella risposta. Fallo solo se non stai lavorando a qualcosa di importante. Lo uso su localhost per accedere a siti Web che ho programmato personalmente.
Chris Dutrow,

3
Downvote da me. Questa è una correzione sporca per far funzionare il tuo codice, ma non una soluzione. La risposta fornita da Артур Курицын è molto meglio.
Ilija,

2
@Bruno Questa è la soluzione perfetta, per script di supporto, test, applicazioni affidabili, intranet, ..... Chiunque conosca UN PICCOLO su SSL, sa in quali casi è possibile saltare la convalida del certificato. Quindi tutti i commenti "intelligenti" su questa risposta e cose come "NON FARE QUESTO" sono proprio NONSENSO !!
Kenyakorn Ketsombut,

5
... " Tutti quelli che conoscono UN PICCOLO su SSL [...] " ... e rimarrai sorpreso da quante persone non si preoccupano nemmeno di conoscere un po 'le basi di SSL / TLS e stanno arrivando qui per copiare / incollare una soluzione rapida per il loro messaggio di errore.
Bruno,

53

Fonte: http://ademar.name/blog/2006/04/curl-ssl-certificate-problem-v.html

Curl: problema con il certificato SSL, verificare che il certificato CA sia OK

07 aprile 2006

Quando apri un URL sicuro con Curl potresti ricevere il seguente errore:

Problema del certificato SSL, verificare che il certificato CA sia OK

Spiegherò perché l'errore e cosa dovresti fare al riguardo.

Il modo più semplice per eliminare l'errore sarebbe aggiungere le seguenti due righe al tuo script. Questa soluzione rappresenta un rischio per la sicurezza.

//WARNING: this would prevent curl from detecting a 'man in the middle' attack
curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0); 

Vediamo cosa fanno questi due parametri. Citando il manuale.

CURLOPT_SSL_VERIFYHOST : 1 per verificare l'esistenza di un nome comune nel certificato peer SSL. 2 per verificare l'esistenza di un nome comune e anche verificare che corrisponda al nome host fornito.

CURLOPT_SSL_VERIFYPEER : FALSE per impedire a CURL di verificare il certificato del peer. È possibile specificare certificati alternativi per la verifica con l'opzione CURLOPT_CAINFO oppure è possibile specificare una directory di certificati con l'opzione CURLOPT_CAPATH. CURLOPT_SSL_VERIFYHOST potrebbe anche essere TRUE o FALSE se CURLOPT_SSL_VERIFYPEER è disabilitato (il valore predefinito è 2). L'impostazione di CURLOPT_SSL_VERIFYHOST su 2 (questo è il valore predefinito) garantirà che il certificato che ti viene presentato ha un "nome comune" corrispondente all'URN che stai utilizzando per accedere alla risorsa remota. Questo è un controllo salutare ma non garantisce che il tuo programma non venga ingannato.

Inserisci "l'uomo al centro"

Il tuo programma potrebbe essere fuorviante nel parlare invece con un altro server. Ciò può essere ottenuto attraverso diversi meccanismi, come l'avvelenamento da dns o arp (Questa è una storia per un altro giorno). L'intruso può anche autofirmare un certificato con lo stesso "nome comune" previsto dal programma. La comunicazione sarebbe ancora crittografata, ma porteresti i tuoi segreti a un impostore. Questo tipo di attacco si chiama "uomo in mezzo"

Sconfiggendo "l'uomo nel mezzo"

Bene, dobbiamo verificare che il certificato che ci viene presentato sia reale. Lo facciamo confrontandolo con un certificato di cui * fidiamo ragionevolmente.

Se la risorsa remota è protetta da un certificato emesso da una delle principali CA come Verisign, GeoTrust et al, è possibile confrontare in modo sicuro con il bundle di certificati CA di Mozilla che è possibile ottenere da http://curl.haxx.se/docs/caextract .html

Salvare il file cacert.pemda qualche parte nel server e impostare le seguenti opzioni nello script.

curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, TRUE); 
curl_setopt ($ch, CURLOPT_CAINFO, "pathto/cacert.pem");

per tutte le informazioni di cui sopra va a: http://ademar.name/blog/2006/04/curl-ssl-certificate-problem-v.html


38
È generalmente considerato cortese accreditare la fonte delle tue informazioni e citare solo alcune parti pertinenti alla domanda, piuttosto che semplicemente copiarle e incollarle qui!
Dan Herd,

1
Scusa, sono stato via, sì, apprezzo Dan per questo e ho aggiornato The Post
Deepak Oberoi il

6
Almeno Deepak ha fatto lo sforzo di ricercarlo. @danherd Quindi, danherd, hai appena fatto delle ricerche per scoprire che ha preso il codice da qualche parte? Qual era il diritto di attribuzione di questo codice? Invece di perdere tempo a cercare gli errori di qualcun altro, cerca di aiutare qualcuno da solo. Non combattere, condividi!
GTodorov,

17

Le soluzioni sopra sono fantastiche, ma se stai usando WampServer potresti trovare che l'impostazione della curl.cainfovariabile php.ininon funziona.

Alla fine ho scoperto che WampServer ha due php.inifile:

C:\wamp\bin\apache\Apachex.x.x\bin
C:\wamp\bin\php\phpx.x.xx

Il primo è apparentemente usato per quando i file PHP sono richiamati attraverso un browser web, mentre il secondo è usato quando un comando è invocato attraverso la riga di comando o shell_exec().

TL; DR

Se si utilizza WampServer, è necessario aggiungere la curl.cainfolinea a entrambi i php.ini file.


6

Per l'amore di tutto ciò che è santo ...

Nel mio caso, ho dovuto impostare la openssl.cafilevariabile di configurazione PHP sul percorso del file PEM.

Credo sia vero che ci sono molti sistemi in cui l'impostazione curl.cainfonella configurazione di PHP è esattamente ciò che è necessario, ma nell'ambiente con cui sto lavorando, che è il contenitore docker eboraas / laravel , che utilizza Debian 8 (jessie) e PHP 5.6, l'impostazione di quella variabile non ha funzionato.

Ho notato che l'output di php -inon ha menzionato nulla di quella particolare impostazione di configurazione, ma aveva alcune righe openssl. C'è sia un'opzione openssl.capathche openssl.cafileun'opzione, ma solo l'impostazione della seconda ha permesso all'arricciatura tramite PHP di essere finalmente a posto con gli URL HTTPS.


Grazie! Anche l'impostazione di curl.cainfo non ha funzionato per me, ma l'impostazione openssl.cafile ha funzionato! Sono su Windows 7 con XAMPP e PHP 7.1.1.
knezmilos,

@knezmilos come hai fatto a impostare il file openssl.cafile? dove hai scaricato e come lo attivi?
Krys,

Bene, è passato un po 'di tempo ma penso che sia qualcosa del genere: curl.cainfo = "C: \ xampp \ cacert \ cacert.pem" e openssl.cafile = "C: \ xampp \ cacert \ cacert.pem" in php. ini, mentre penso di aver ottenuto il file pem da una delle risposte qui.
knezmilos,

1
"Per l'amore di tutto ciò che è santo ..." in effetti. Questo ha funzionato per la mia installazione di Ubuntu 18.08 / Apache / Php7.2. Se l'errore di arricciatura punta al file giusto, allora è sicuramente colpa di openssls
JTG

4

A volte se l'applicazione che si tenta di contattare ha certificati autofirmati, il normale cacert.pem da http://curl.haxx.se/ca/cacert.pem non risolve il problema.

Se si è sicuri dell'URL dell'endpoint del servizio, selezionarlo tramite il browser, salvare il certificato manualmente nel formato "Certificato X 509 con catena (PEM)". Punta questo file di certificato con il

curl_setopt ($ch, CURLOPT_CAINFO, "pathto/{downloaded certificate chain file}");   

4

Ho lo stesso errore su Amazon AMI Linux.

Ho risolto impostando curl.cainfo su /etc/php.d/curl.ini

https://gist.github.com/reinaldomendes/97fb2ce8a606ec813c4b

Aggiunta ottobre 2018

Su Amazon Linux v1 modifica questo file

vi /etc/php.d/20-curl.ini

Per aggiungere questa riga

curl.cainfo="/etc/ssl/certs/ca-bundle.crt"

Perfetto grazie! Ho aggiornato la domanda per aggiungere esattamente quello che ho fatto che ha risolto il problema per me, piuttosto che creare un'altra risposta.
Tim

3

Quando si impostano le opzioni di arricciatura per CURLOPT_CAINFO, ricordare di utilizzare virgolette singole, l'uso di virgolette doppie causerà solo un altro errore. Quindi la tua opzione dovrebbe apparire come:

curl_setopt ($ch, CURLOPT_CAINFO, 'c:\wamp\www\mywebfolder\cacert.pem');

Inoltre, nel tuo file php.ini l'impostazione dovrebbe essere scritta come: (nota le mie doppie virgolette)

curl.cainfo = "C:\wamp\www\mywebfolder"

L'ho messo direttamente sotto la linea che dice questo: extension=php_curl.dll

(Solo per scopi organizzativi, potresti metterlo ovunque nel tuo php.ini, l'ho appena messo vicino a un altro riferimento di arricciatura, quindi quando cerco usando la parola chiave arricciatura posso trovare entrambi i riferimenti di arricciatura in un'area.)


1
Spero che php.ini dovrebbe puntare al file pem anziché alla sua cartella principale
dejjub-AIS,

2

Sono finito qui quando ho cercato di ottenere GuzzleHttp (php + apache su Mac) per ottenere una pagina da www.googleapis.com.

Ecco la mia soluzione finale nel caso in cui aiuti qualcuno.

Guarda la catena di certificati per qualunque dominio ti stia dando questo errore. Per me è stato googleapis.com

openssl s_client -host www.googleapis.com -port 443

Riceverai qualcosa del genere:

Certificate chain
 0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=*.googleapis.com
   i:/C=US/O=Google Inc/CN=Google Internet Authority G2
 1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2
   i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
 2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
   i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority

Nota: l'ho catturato dopo aver risolto il problema, l'output della catena potrebbe avere un aspetto diverso.

Quindi devi guardare i certificati consentiti in php. Esegui phpinfo () in una pagina.

<?php echo phpinfo();

Quindi cerca il file del certificato caricato dall'output della pagina:

openssl.cafile  /usr/local/php5/ssl/certs/cacert.pem

Questo è il file che dovrai correggere aggiungendo i certificati corretti.

sudo nano /usr/local/php5/ssl/certs/cacert.pem

Fondamentalmente è necessario aggiungere le "firme" del certificato corrette alla fine di questo file.

Puoi trovarne alcuni qui: potrebbe essere necessario cercare su Google / cercare altri nella catena se ne hai bisogno.

Sembrano così:

immagine di esempio di certificato

( Nota: questa è un'immagine in modo che le persone non copieranno / incollino semplicemente i certificati dallo stackoverflow )

Una volta che i certificati giusti sono in questo file, riavvia apache ed esegui il test.


0

È possibile provare a reinstallare il ca-certificatespacchetto o consentire esplicitamente il certificato in questione, come descritto qui .


-5

La soluzione è molto semplice! Inserisci questa riga prima di curl_exec:

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);

Per me funziona.


7
Mai e poi mai disabilitare la verifica tra pari, a meno che non ti interessi se i dati sono compromessi durante il trasporto.
rdlowrey,

Concordato. Se si desidera un'app sicura, è necessaria la verifica tra pari.
Brad

2
"Mai, mai disabilitare la verifica tra pari" A MENO CHE non si desideri la funzionalità predefinita del browser haha. Inoltre, perché questo è downvoted così tanto? Questa è l'unica risposta breve, dolce, precisa ed efficace.
Adam F,

@AdamF FYI, i browser verificano il certificato peer per impostazione predefinita, ti danno solo la possibilità di bypassare gli errori manualmente, con un avviso.
Bruno,
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.