file_get_contents (): operazione SSL non riuscita con il codice 1, impossibile abilitare la crittografia


188

Ho cercato di accedere a questo particolare servizio REST da una pagina PHP che ho creato sul nostro server. Ho ristretto il problema a queste due righe. Quindi la mia pagina PHP è simile a questa:

<?php
$response = file_get_contents("https://maps.co.weber.ut.us/arcgis/rest/services/SDE_composite_locator/GeocodeServer/findAddressCandidates?Street=&SingleLine=3042+N+1050+W&outFields=*&outSR=102100&searchExtent=&f=json");

echo $response; ?>

La pagina muore alla riga 2 con i seguenti errori:

  • Avvertenza: file_get_contents (): operazione SSL non riuscita con codice 1. Messaggi di errore OpenSSL: errore: 14090086: routine SSL: SSL3_GET_SERVER_CERTIFICATE: verifica del certificato non riuscita in ... php sulla linea 2
    • Attenzione: file_get_contents (): Impossibile abilitare crypto in ... php sulla linea 2
    • Avviso: file_get_contents ( https://maps.co.weber.ut.us/arcgis/rest/services/SDE_composite_locator/GeocodeServer/findAddressCandidates?Street=&SingleLine=3042+N+1050+W&outFields=*&outSR=102100&searchExtent=&f=json) : impossibile aprire il flusso: operazione non riuscita in ... php sulla linea 2

Stiamo usando un server Gentoo. Di recente abbiamo aggiornato alla versione 5.6 di PHP. È stato dopo l'aggiornamento quando è apparso questo problema.

Ho trovato quando sostituisco il servizio REST con un indirizzo simile https://www.google.com; la mia pagina funziona bene.

In un tentativo precedente ho impostato “verify_peer”=>falsee passato questo come argomento a file_get_contents, come descritto qui: file_get_contents ignorando verifica_peer => false? Ma come ha notato lo scrittore; non ha fatto differenza.

Ho chiesto a uno dei nostri amministratori di server se esistono queste righe nel nostro file php.ini:

  • extension = php_openssl.dll
  • allow_url_fopen = Attivo

Mi ha detto che da quando siamo su Gentoo, openssl viene compilato quando costruiamo; e non è impostato nel file php.ini.

Ho anche confermato che allow_url_fopenfunziona. A causa della natura specializzata di questo problema; Non trovo molte informazioni di aiuto. Qualcuno di voi ha incontrato qualcosa del genere? Grazie.


Se si utilizza Kaspersky, controllare questo: stackoverflow.com/a/54791481/3549317
Cespon

Risposte:


344

Questo è stato un link estremamente utile per trovare:

http://php.net/manual/en/migration56.openssl.php

Un documento ufficiale che descrive le modifiche apportate per aprire ssl in PHP 5.6 Da qui ho appreso un altro parametro che avrei dovuto impostare su false: "confirm_peer_name" => false

Nota: questo ha implicazioni di sicurezza molto significative. La disabilitazione della verifica consente potenzialmente a un utente malintenzionato MITM di utilizzare un certificato non valido per intercettare le richieste. Mentre può essere utile farlo nello sviluppo locale, altri approcci dovrebbero essere usati nella produzione.

Quindi il mio codice di lavoro è simile al seguente:

<?php
$arrContextOptions=array(
    "ssl"=>array(
        "verify_peer"=>false,
        "verify_peer_name"=>false,
    ),
);  

$response = file_get_contents("https://maps.co.weber.ut.us/arcgis/rest/services/SDE_composite_locator/GeocodeServer/findAddressCandidates?Street=&SingleLine=3042+N+1050+W&outFields=*&outSR=102100&searchExtent=&f=json", false, stream_context_create($arrContextOptions));

echo $response; ?>

122
questo rompe la certificazione SSL ed è un buco nella sicurezza
hypery2k il

8
Come ha sottolineato @ hypery2k, non dovresti semplicemente disabilitare la verifica. Vedi la mia risposta per una soluzione alternativa che non vanifica lo scopo di usare ssl.
elitechief21,

4
Questo davvero non dovrebbe essere fatto. Invece di aggirare il problema, dovresti effettivamente risolverlo. Scopri la soluzione migliore da @ elitechief21.
Jasper

5
Questo può essere frustrante se stai testando da un ambiente locale contro un API. In questo caso normalmente mi occupo della verifica.
HappyCoder

12
Dato che vengo sempre qui quando provo a fare questo, ecco il codice per copiare e incollare facilmente:file_get_contents($url, false, stream_context_create(array('ssl' => array('verify_peer' => false, 'verify_peer_name' => false))));
laurent

154

Non dovresti semplicemente disattivare la verifica. Piuttosto dovresti scaricare un pacchetto di certificati, forse il pacchetto arricciatura farà?

Quindi devi solo metterlo sul tuo server web, dando all'utente che esegue il permesso php per leggere il file. Quindi questo codice dovrebbe funzionare per te:

$arrContextOptions=array(
    "ssl"=>array(
        "cafile" => "/path/to/bundle/cacert.pem",
        "verify_peer"=> true,
        "verify_peer_name"=> true,
    ),
);

$response = file_get_contents("https://maps.co.weber.ut.us/arcgis/rest/services/SDE_composite_locator/GeocodeServer/findAddressCandidates?Street=&SingleLine=3042+N+1050+W&outFields=*&outSR=102100&searchExtent=&f=json", false, stream_context_create($arrContextOptions));

Si spera che il certificato radice del sito a cui si sta tentando di accedere sia nel bundle di arricciatura. In caso contrario, ciò non funzionerà fino a quando non si ottiene il certificato radice del sito e lo si inserisce nel file del certificato.


Da dove viene il file .crt? Non ci sono collegamenti nel sito web di curl che fornisci solo con .pem.
Vee

1
Il file pem dovrebbe essere lo stesso. Al momento della pubblicazione, avevano due versioni del pacchetto di certificati sul loro sito, una pem e una crt e ho appena usato il file crt per il mio esempio (naturalmente è quello che avrebbero rimosso). Per riferimento futuro, i file crt vengono generalmente rinominati file pem, che vengono rinominati in modo che Windows riconosca il file come file di certificato. Questo non sarà sempre il caso, ma è in questo caso. Aggiornerò il mio esempio in modo che utilizzi il file pem attualmente sul sito di arricciatura
elitechief21

4
c'è anche una funzione utile stream_context_set_defaultche può essere utilizzata in modo da non doverlo passare ogni volta in file_get_contents
Ken Koch,

Qualcuno l'ha mai fatto funzionare? Ho provato con il bundle cacert.pem collegato a questa risposta e anche con il certificato radice CA Comodo (che è la radice CA per il certificato che voglio verificare), ma fallirà sempre.
Zmippie,

1
Dal punto di vista della sicurezza: accanto all'uso dell'opzione di contesto del flusso cafile, potrebbe essere molto importante definire anche le cifre consentite nell'opzione di contesto del flusso di cifre e vietare quelle versioni SSL che sono conosciute come vulnerabili. Si consiglia inoltre di impostare l'opzione di contesto di flusso disable_compression su true per mitigare il vettore di attacco CRIME.
Josef Glatz,

36

Ho risolto questo problema assicurandomi che OpenSSL fosse installato sul mio computer e quindi aggiungendolo al mio php.ini:

openssl.cafile=/usr/local/etc/openssl/cert.pem

@Akhi Dovresti essere in grado di trovare alcuni tutorial se lo cerchi su Google
andlin

2
Ho usato lo stesso metodo usando PHP 7 su IIS, scaricato il cert.pemfile e impostato php.inicosì, e ha funzionato:openssl.cafile=D:\Tools\GnuWin32\bin\cacert.pem
David Refoua,

1
Ho scaricato il file PEM da curl.haxx.se/docs/caextract.html - risolto il problema per me su Windows con un particolare URL gstatic.com.
Jake,

Il download del file PEM da curl.haxx.se/docs/caextract.html non ha funzionato per me su Centos 7. Ho creato un certificato bundle concatenando il certificato principale e pkcs7 e lo posiziono sul server, quindi specifica il percorso openssl.cafile. +1 per la giusta risposta e direzione.
Arvind K.

Quando si crea un pacchetto, non dimenticare di convertire pkcs in file pem prima di concederlo alla certificazione principale
Arvind K.

22

Puoi aggirare questo problema scrivendo una funzione personalizzata che utilizza l'arricciatura, come in:

function file_get_contents_curl( $url ) {

  $ch = curl_init();

  curl_setopt( $ch, CURLOPT_AUTOREFERER, TRUE );
  curl_setopt( $ch, CURLOPT_HEADER, 0 );
  curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
  curl_setopt( $ch, CURLOPT_URL, $url );
  curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, TRUE );

  $data = curl_exec( $ch );
  curl_close( $ch );

  return $data;

}

Quindi usa file_get_contents_curlinvece invece file_get_contentsogni volta che chiami un URL che inizia con https.


Questo ha funzionato per me. Ottimo lavoro e grazie!
Nick Green,

11

Lavorando per me, sto usando PHP 5.6. L'estensione openssl dovrebbe essere abilitata e mentre chiami google map api confirm_peer make false Il codice sottostante funziona per me.

<?php
$arrContextOptions=array(
    "ssl"=>array(
         "verify_peer"=>false,
         "verify_peer_name"=>false,
    ),
);  
$url = "https://maps.googleapis.com/maps/api/geocode/json?latlng="
      . $latitude
      . ","
      . $longitude
      . "&sensor=false&key="
      . Yii::$app->params['GOOGLE_API_KEY'];

$data = file_get_contents($url, false, stream_context_create($arrContextOptions));

echo $data;
?>

10

Se la tua versione di PHP è 5, prova a installare cURL digitando il seguente comando nel terminale:

sudo apt-get install php5-curl

9
Questo non ha assolutamente nulla a che fare con cURL.
Andreas,

2
L'installazione del php curl dovrebbe essere la risposta corretta! Per il mio sistema Mac, sto usando port, e il comando è:sudo port install php70-curl
hailong


6

i seguenti passaggi risolveranno questo problema,

  1. Scarica il certificato CA da questo link: https://curl.haxx.se/ca/cacert.pem
  2. Trova e apri php.ini
  3. Cerca curl.cainfoe incolla il percorso assoluto da cui hai scaricato il certificato.curl.cainfo ="C:\wamp\htdocs\cert\cacert.pem"
  4. Riavvia WAMP / XAMPP (server Apache).
  5. Funziona!

spero che aiuti !!


è sicuro? amo le soluzioni semplici ma qui mi mancano alcune informazioni ..
swisswiss,

per i test va bene
Geomorillo,

5

Volevo solo aggiungere a questo poiché ho riscontrato lo stesso problema e nulla che potessi trovare da nessuna parte avrebbe funzionato (ad esempio, scaricare il file cacert.pem, impostare cafile in php.ini ecc.)

Se si utilizza NGINX e il certificato SSL viene fornito con un "certificato intermedio", è necessario combinare il file di certificato intermedio con il file principale "mydomain.com.crt" e dovrebbe funzionare. Apache ha un'impostazione specifica per certificati intermedi, ma NGINX non lo fa, quindi deve trovarsi nello stesso file del tuo certificato normale.


4

Il motivo di questo errore è che PHP non ha un elenco di autorità di certificazione attendibili.

PHP 5.6 e versioni successive tentano di caricare automaticamente le autorità di certificazione attendibili dal sistema. I problemi che possono essere risolti. Vedi http://php.net/manual/en/migration56.openssl.php per maggiori informazioni.

PHP 5.5 e precedenti sono davvero difficili da configurare correttamente poiché devi specificare manualmente il bundle CA in ogni contesto di richiesta, una cosa che non vuoi cospargere attorno al tuo codice. Quindi ho deciso per il mio codice che per le versioni di PHP <5.6, la verifica SSL viene semplicemente disabilitata:

$req = new HTTP_Request2($url);
if (version_compare(PHP_VERSION, '5.6.0', '<')) {
    //correct ssl validation on php 5.5 is a pain, so disable
    $req->setConfig('ssl_verify_host', false);
    $req->setConfig('ssl_verify_peer', false);
}

Questo mi ha aiutato a trovare il mio problema. Anche se sono su PHP 5.6, stavo usando una libreria client API obsoleta che specificava manualmente un vecchio file CA usando l'opzione di contesto cafile come da link sopra. Rimuovendolo dalla libreria del client API ho risolto il problema per me. Presumibilmente PHP ha iniziato a utilizzare il bundle di fiducia OpenSSLs
Joe Lipson

4

Ha avuto lo stesso errore con PHP 7 su XAMPP e OSX.

La risposta sopra menzionata in https://stackoverflow.com/ è buona, ma non ha risolto completamente il problema per me. Ho dovuto fornire la catena di certificati completa per far funzionare nuovamente file_get_contents (). È così che l'ho fatto:

Ottieni il certificato root / intermedio

Prima di tutto ho dovuto capire qual è la radice e il certificato intermedio.

Il modo più conveniente è forse uno strumento di certificazione online come lo ssl-shopper

Lì ho trovato tre certificati, un certificato server e due certificati catena (uno è il root, l'altro apparentemente l'intermedio).

Tutto quello che devo fare è solo cercare su Internet per entrambi. Nel mio caso, questa è la radice:

thawte DV SSL SHA256 CA

E conduce al suo url thawte.com . Quindi ho appena inserito questo certificato in un file di testo e ho fatto lo stesso per l'intermedio. Fatto.

Ottieni il certificato host

La prossima cosa che ho dovuto fare è scaricare il mio certificato server. Su Linux o OS X si può fare con openssl:

openssl s_client -showcerts -connect whatsyoururl.de:443 </dev/null 2>/dev/null|openssl x509 -outform PEM > /tmp/whatsyoururl.de.cert

Ora riuniscili tutti

Ora uniscili tutti in un unico file. (Forse è bene metterli in una cartella, li ho uniti in un unico file). Puoi farlo in questo modo:

cat /tmp/thawteRoot.crt > /tmp/chain.crt
cat /tmp/thawteIntermediate.crt >> /tmp/chain.crt
cat /tmp/tmp/whatsyoururl.de.cert >> /tmp/chain.crt

dire a PHP dove trovare la catena

C'è questa utile funzione openssl_get_cert_locations () che ti dirà dove PHP sta cercando i file cert. E c'è questo parametro, che dirà a file_get_contents () dove cercare i file cert. Forse entrambi i modi funzioneranno. Ho preferito il modo di parametro. (Rispetto alla soluzione sopra menzionata).

Quindi questo è ora il mio codice PHP

$arrContextOptions=array(
    "ssl"=>array(
        "cafile" => "/Applications/XAMPP/xamppfiles/share/openssl/certs/chain.pem",
        "verify_peer"=> true,
        "verify_peer_name"=> true,
    ),
);

$response = file_get_contents($myHttpsURL, 0, stream_context_create($arrContextOptions));

È tutto. file_get_contents () funziona di nuovo. Senza CURL e si spera senza difetti di sicurezza.


Qual è il file chain.pem? È questo chain.crt?
Dr.X,

Non è chain.crt, è per il certificato effettivo. È la lista dei certificati intermedi, nota anche come catena di certificati. Non ne hai necessariamente bisogno. Utilizza un controllo certificati SSL per scoprire se ne hai bisogno. In tal caso, puoi cercare il nome del tuo emittente certificato + il termine "catena" o "intermedio" per trovare il file corretto.
n.

4

Dopo essere caduto vittima di questo problema su centOS dopo aver aggiornato php a php5.6 ho trovato una soluzione che ha funzionato per me.

Ottieni la directory corretta per i tuoi certificati da posizionare di default con questo

php -r 'print_r(openssl_get_cert_locations()["default_cert_file"]);'

Quindi usa questo per ottenere il certificato e metterlo nella posizione predefinita trovata dal codice sopra

wget http://curl.haxx.se/ca/cacert.pem -O <default location>

3

Ho avuto lo stesso problema ssl sulla mia macchina sviluppatore (php 7, xampp su windows) con un certificato autofirmato che cercava di aprire un file " https: // localhost / ...". Ovviamente il root-certificate-assembly (cacert.pem) non ha funzionato. Ho appena copiato manualmente il codice dall'apache server.crt-File nel file cacert.pem scaricato e ho eseguito openssl.cafile = path / to / cacert.pem in php.ini


2

Un'altra cosa da provare è reinstallare ca-certificatescome dettagliato qui .

# yum reinstall ca-certificates
...
# update-ca-trust force-enable 
# update-ca-trust extract

E un'altra cosa da provare è consentire esplicitamente il certificato di un sito in questione come descritto qui (specialmente se l'unico sito è il tuo server e hai già il .pem a portata di mano).

# cp /your/site.pem /etc/pki/ca-trust/source/anchors/
# update-ca-trust extract

Stavo riscontrando questo esatto errore SO dopo l'aggiornamento a PHP 5.6 su CentOS 6 tentando di accedere al server stesso che ha un certificato di sicurezza cheapsslsecurity che forse doveva essere aggiornato, ma invece ho installato un certificato letsencrypt e con questi due passaggi sopra ha fatto il trucco. Non so perché il secondo passo fosse necessario.


Comandi utili

Visualizza la versione di openssl:

# openssl version
OpenSSL 1.0.1e-fips 11 Feb 2013

Visualizza le impostazioni correnti di PHP cli ssl:

# php -i | grep ssl
openssl
Openssl default config => /etc/pki/tls/openssl.cnf
openssl.cafile => no value => no value
openssl.capath => no value => no value

1

Per quanto riguarda gli errori simili a

[11-mag-2017 19:19:13 America / Chicago] Avviso PHP: file_get_contents (): operazione SSL non riuscita con codice 1. Messaggi di errore OpenSSL: errore: 14090086: routine SSL: ssl3_get_server_certificate: verifica certificato non riuscita

Hai controllato le autorizzazioni del certificato e delle directory a cui fa riferimento openssl?

Puoi farlo

var_dump(openssl_get_cert_locations());

Per ottenere qualcosa di simile a questo

array(8) {
  ["default_cert_file"]=>
  string(21) "/usr/lib/ssl/cert.pem"
  ["default_cert_file_env"]=>
  string(13) "SSL_CERT_FILE"
  ["default_cert_dir"]=>
  string(18) "/usr/lib/ssl/certs"
  ["default_cert_dir_env"]=>
  string(12) "SSL_CERT_DIR"
  ["default_private_dir"]=>
  string(20) "/usr/lib/ssl/private"
  ["default_default_cert_area"]=>
  string(12) "/usr/lib/ssl"
  ["ini_cafile"]=>
  string(0) ""
  ["ini_capath"]=>
  string(0) ""
}

Questo problema mi ha frustrato per un po ', fino a quando ho capito che la mia cartella "certs" aveva 700 autorizzazioni, quando avrebbe dovuto avere 755 autorizzazioni. Ricorda, questa non è la cartella per le chiavi ma i certificati. Consiglio di leggere questo link su permessi ssl.

Una volta l'ho fatto

chmod 755 certs

Il problema è stato risolto, almeno per me comunque.


Sìì! Anche CHMOD era il mio problema ;-) Grazie
RA.

0

Ho avuto lo stesso problema per un'altra pagina sicura durante l'utilizzo di wgetofile_get_contents . Molte ricerche (incluse alcune delle risposte a questa domanda) hanno portato a una soluzione semplice - l'installazione di Curl e PHP-Curl - Se ho capito bene, Curl ha la CA principale per Comodo che ha risolto il problema

Installa il componente aggiuntivo Curl e PHP-Curl, quindi riavvia Apache

sudo apt-get install curl
sudo apt-get install php-curl
sudo /etc/init.d/apache2 reload

Tutto ora funziona.

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.