file_get_contents (): SSL-Vorgang mit Code 1 fehlgeschlagen. Krypto konnte nicht aktiviert werden

187

Ich habe versucht, über eine PHP-Seite, die ich auf unserem Server erstellt habe, auf diesen bestimmten REST-Service zuzugreifen. Ich habe das Problem auf diese beiden Zeilen eingegrenzt. Meine PHP-Seite sieht also so aus:

<?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; ?>

Die Seite stirbt in Zeile 2 mit folgenden Fehlern:

  • Warnung: file_get_contents (): SSL-Vorgang mit Code 1 fehlgeschlagen. OpenSSL-Fehlermeldungen: Fehler: 14090086: SSL-Routinen: SSL3_GET_SERVER_CERTIFICATE: Zertifikatüberprüfung in ... PHP in Zeile 2 fehlgeschlagen
    • Warnung: file_get_contents (): Krypto in ... php in Zeile 2 konnte nicht aktiviert werden
    • Warnung: 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): Stream konnte nicht geöffnet werden: Vorgang in ... php in Zeile 2 fehlgeschlagen

Wir verwenden einen Gentoo-Server. Wir haben kürzlich ein Upgrade auf PHP Version 5.6 durchgeführt. Es war nach dem Upgrade, als dieses Problem auftrat.

Ich habe festgestellt, wenn ich den REST-Service durch eine Adresse wie: https://www.google.comErsetze. Meine Seite funktioniert einwandfrei.

In einem früheren Versuch habe ich das festgelegt “verify_peer”=>falseund als Argument an file_get_contents übergeben, wie hier beschrieben: file_get_contents ignoriert verify_peer => false? Aber wie der Schriftsteller feststellte; es machte keinen Unterschied.

Ich habe einen unserer Serveradministratoren gefragt, ob diese Zeilen in unserer Datei php.ini vorhanden sind:

  • extension = php_openssl.dll
  • allow_url_fopen = Ein

Er sagte mir, dass openssl kompiliert wird, wenn wir bauen, da wir auf Gentoo sind. und es ist nicht in der Datei php.ini festgelegt.

Ich habe auch bestätigt, dass allow_url_fopendas funktioniert. Aufgrund der Spezialität dieses Problems; Ich finde nicht viele Informationen für Hilfe. Ist jemand von euch auf so etwas gestoßen? Vielen Dank.

Joe
quelle
Wenn Sie Kaspersky verwenden, überprüfen Sie dies: stackoverflow.com/a/54791481/3549317
cespon

Antworten:

338

Dies war ein enorm hilfreicher Link zu finden:

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

Ein offizielles Dokument, das die Änderungen beschreibt, die zum Öffnen von ssl in PHP 5.6 vorgenommen wurden. Von hier aus erfuhr ich von einem weiteren Parameter, den ich auf false hätte setzen sollen: "verify_peer_name" => false

Hinweis: Dies hat sehr erhebliche Auswirkungen auf die Sicherheit. Durch Deaktivieren der Überprüfung kann ein MITM-Angreifer möglicherweise ein ungültiges Zertifikat verwenden, um die Anforderungen zu belauschen. Während dies in der lokalen Entwicklung nützlich sein kann, sollten in der Produktion andere Ansätze verwendet werden.

Mein Arbeitscode sieht also so aus:

<?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; ?>
Joe
quelle
122
Dies bricht die SSL-Zertifizierung und ist eine Sicherheitslücke
hypery2k
8
Wie @ hypery2k hervorhob, sollten Sie die Überprüfung nicht einfach deaktivieren. In meiner Antwort finden Sie eine alternative Lösung, die den Zweck der Verwendung von ssl nicht zunichte macht.
Elitechief21
4
Das sollte wirklich nicht gemacht werden. Anstatt das Problem zu umgehen, sollten Sie es tatsächlich beheben. Sehen Sie die bessere Lösung von @ Elitechief21.
Jasper
5
Dies kann frustrierend sein, wenn Sie in einer lokalen Umgebung gegen eine API testen. In diesem Fall mache ich normalerweise eine Nuklearprüfung.
HappyCoder
12
Da ich immer hierher komme, wenn ich das versuche, ist hier der Code zum einfachen Kopieren und Einfügen:file_get_contents($url, false, stream_context_create(array('ssl' => array('verify_peer' => false, 'verify_peer_name' => false))));
Laurent
153

Sie sollten die Überprüfung nicht einfach deaktivieren. Eher sollten Sie ein Zertifikatspaket herunterladen, vielleicht reicht das Curl- Bundle?

Dann müssen Sie es nur noch auf Ihren Webserver stellen und dem Benutzer, der PHP ausführt, die Berechtigung zum Lesen der Datei erteilen. Dann sollte dieser Code für Sie funktionieren:

$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));

Hoffentlich befindet sich das Stammzertifikat der Site, auf die Sie zugreifen möchten, im Curl-Bundle. Wenn dies nicht der Fall ist, funktioniert dies immer noch nicht, bis Sie das Stammzertifikat der Site erhalten und in Ihre Zertifikatdatei einfügen.

Elitechief21
quelle
Woher kommt die CRT-Datei? Es gibt keinen Link in der Curl-Website, die Sie bereitstellen. Sie haben nur .pem.
Vee
1
Die PEM-Datei sollte identisch sein. Zum Zeitpunkt der Veröffentlichung hatten sie zwei Versionen des Zertifikatspakets auf ihrer Website, ein PEM und ein CRT, und ich habe nur die CRT-Datei für mein Beispiel verwendet (natürlich ist dies diejenige, die sie entfernen würden). Zur späteren Bezugnahme werden CRT-Dateien normalerweise in PEM-Dateien umbenannt, die so umbenannt werden, dass Windows die Datei als Zertifikatdatei erkennt. Dies wird nicht immer der Fall sein, aber es ist in diesem Fall. Ich werde mein Beispiel so aktualisieren, dass es die PEM-Datei verwendet, die sich derzeit auf der Curl-Site befindet
Elitechief21
4
Es gibt auch eine hilfreiche Funktion, stream_context_set_defaultdie verwendet werden kann, damit Sie sie nicht jedes Mal an file_get_contents übergeben müssen
Ken Koch
Hat jemand das jemals zum Laufen gebracht? Ich habe es mit dem in dieser Antwort verknüpften cacert.pem-Bundle und auch mit dem Comodo-CA-Stammzertifikat (dem CA-Stammzertifikat für das Zertifikat, das ich überprüfen lassen möchte) versucht, aber es wird immer fehlschlagen.
Zmippie
1
Aus Sicherheitsgründen: Neben der Verwendung der Kontextoption cafile stream kann es sehr wichtig sein, auch die zulässigen Chiffren in der Kontextoption ciphers stream zu definieren und die als anfällig bekannten SSL-Versionen zu verbieten. Es wird auch empfohlen, die Stream-Kontextoption disable_compression auf true zu setzen, um den CRIME-Angriffsvektor zu verringern.
Josef Glatz
36

Ich habe dies behoben, indem ich sichergestellt habe, dass OpenSSL auf meinem Computer installiert ist, und dies dann zu meiner php.ini hinzugefügt habe:

openssl.cafile=/usr/local/etc/openssl/cert.pem
andlin
quelle
@Akhi Sie sollten in der Lage sein, einige Tutorials zu finden, wenn Sie es
googeln
2
Ich habe die gleiche Methode mit PHP 7 auf IIS verwendet, die cert.pemDatei heruntergeladen und php.iniopenssl.cafile=D:\Tools\GnuWin32\bin\cacert.pem
Folgendes festgelegt
1
Ich habe die PEM-Datei von curl.haxx.se/docs/caextract.html heruntergeladen und das Problem unter Windows mit einer bestimmten gstatic.com-URL behoben.
Jake
Das Herunterladen der PEM-Datei von curl.haxx.se/docs/caextract.html funktionierte unter Centos 7 nicht. Ich habe ein Bundle-Zertifikat erstellt, indem ich das Hauptzertifikat und pkcs7 verkettet und auf dem Server abgelegt und dann den Pfad openssl.cafile angegeben habe. +1 für die richtige Antwort und Richtung.
Arvind K.
Vergessen Sie beim Erstellen eines Bundles nicht, pkcs in pem-Dateien zu konvertieren, bevor Sie es auf die Hauptzertifizierung übertragen
Arvind K.
21

Sie können dieses Problem umgehen, indem Sie eine benutzerdefinierte Funktion schreiben, die Curl verwendet, wie 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;

}

Verwenden Sie dann einfach file_get_contents_curlstatt file_get_contentswann immer Sie eine URL aufrufen, die mit https beginnt.

Ben Shoval
quelle
Das hat bei mir funktioniert. Tolle Arbeit und danke!
Nick Green
12

Ich arbeite für mich und verwende PHP 5.6. Die openssl-Erweiterung sollte aktiviert sein und beim Aufrufen von google map api verify_peer make false Der folgende Code funktioniert für mich.

<?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;
?>
Dipti
quelle
10

Wenn Ihre PHP-Version 5 ist, versuchen Sie, cURL zu installieren, indem Sie den folgenden Befehl in das Terminal eingeben:

sudo apt-get install php5-curl
ARUNBALAN NV
quelle
9
Das hat absolut nichts damit zu tun cURL.
Andreas
2
Die Installation der PHP Curl sollte die richtige Antwort sein! Für mein Mac-System verwende ich Port und der Befehl lautet:sudo port install php70-curl
hailong
6

Die folgenden Schritte beheben dieses Problem.

  1. Laden Sie das CA-Zertifikat über diesen Link herunter: https://curl.haxx.se/ca/cacert.pem
  2. Finde und öffne php.ini
  3. Suchen Sie nach curl.cainfodem absoluten Pfad, in den Sie das Zertifikat heruntergeladen haben, und fügen Sie ihn ein.curl.cainfo ="C:\wamp\htdocs\cert\cacert.pem"
  4. Starten Sie WAMP / XAMPP (Apache-Server) neu.
  5. Es klappt!

hoffentlich hilft das !!

akee93
quelle
ist das sicher Ich liebe einfache Lösungen, aber ich vermisse einige Informationen hier ..
Schweizer
zum Testen ist ok
Geomorillo
5

Ich wollte nur etwas hinzufügen, da ich auf dasselbe Problem stieß und nichts, was ich irgendwo finden konnte, funktionieren würde (z. B. Herunterladen der Datei cacert.pem, Festlegen von cafile in php.ini usw.)

Wenn Sie NGINX verwenden und Ihr SSL-Zertifikat mit einem "Zwischenzertifikat" geliefert wird, müssen Sie die Zwischenzertifikatsdatei mit Ihrer Hauptdatei "mydomain.com.crt" kombinieren, und es sollte funktionieren. Apache hat eine spezielle Einstellung für Zwischenzertifikate, NGINX jedoch nicht. Sie muss sich in derselben Datei befinden wie Ihr reguläres Zertifikat.

SlickTheNick
quelle
4

Grund für diesen Fehler ist, dass PHP keine Liste vertrauenswürdiger Zertifizierungsstellen hat.

PHP 5.6 und höher versuchen, die vom System vertrauenswürdigen Zertifizierungsstellen automatisch zu laden. Probleme damit können behoben werden. Siehe http://php.net/manual/en/migration56.openssl.phpWeitere Informationen finden .

PHP 5.5 und frühere Versionen sind sehr schwer korrekt einzurichten, da Sie das CA-Bundle in jedem Anforderungskontext manuell angeben müssen, was Sie nicht um Ihren Code streuen möchten. Deshalb habe ich für meinen Code entschieden, dass für PHP-Versionen <5.6 die SSL-Überprüfung einfach deaktiviert wird:

$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);
}
cweiske
quelle
Dies hat mir geholfen, mein Problem zu finden. Obwohl ich mit PHP 5.6 arbeite, habe ich eine veraltete API-Client-Bibliothek verwendet, die manuell eine alte CA-Datei mithilfe der Cafile-Kontextoption gemäß dem obigen Link angegeben hat. Das Entfernen aus der API-Client-Bibliothek hat es für mich behoben. Vermutlich hat PHP begonnen, das vertrauenswürdige OpenSSL-Bundle zu verwenden
Joe Lipson
4

Hatte den gleichen Fehler mit PHP 7 unter XAMPP und OSX.

Die oben erwähnte Antwort in https://stackoverflow.com/ ist gut, aber sie hat das Problem für mich nicht vollständig gelöst. Ich musste die vollständige Zertifikatkette bereitstellen, damit file_get_contents () wieder funktioniert. So habe ich es gemacht:

Holen Sie sich das Root- / Zwischenzertifikat

Zuerst musste ich herausfinden, was die Wurzel ist und das Zwischenzertifikat ist.

Der bequemste Weg ist vielleicht ein Online-Zertifizierungs-Tool wie der SSL-Shopper

Dort fand ich drei Zertifikate, ein Serverzertifikat und zwei Kettenzertifikate (eines ist die Wurzel, das andere anscheinend das Zwischenprodukt).

Ich muss nur im Internet nach beiden suchen. In meinem Fall ist dies die Wurzel:

DV SSL SHA256 CA auftauen

Und es führt zu seiner URL thawte.com . Also habe ich dieses Zertifikat einfach in eine Textdatei eingefügt und das Gleiche für die Zwischenstufe getan. Getan.

Holen Sie sich das Host-Zertifikat

Als nächstes musste ich mein Serverzertifikat herunterladen. Unter Linux oder OS X kann dies mit openssl erfolgen:

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

Jetzt bring sie alle zusammen

Führen Sie jetzt einfach alle in einer Datei zusammen. (Vielleicht ist es gut, sie einfach in einen Ordner zu legen, ich habe sie nur in einer Datei zusammengeführt). Sie können es so machen:

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

Sagen Sie PHP, wo sich die Kette befindet

Es gibt diese praktische Funktion openssl_get_cert_locations (), die Ihnen sagt, wo PHP nach Zertifizierungsdateien sucht. Und es gibt diesen Parameter, der file_get_contents () mitteilt, wo nach Zertifizierungsdateien gesucht werden soll. Vielleicht funktionieren beide Wege. Ich habe den Parameter Weg bevorzugt. (Im Vergleich zu der oben genannten Lösung).

Das ist jetzt mein PHP-Code

$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));

Das ist alles. file_get_contents () funktioniert wieder. Ohne CURL und hoffentlich ohne Sicherheitslücken.

nr
quelle
Was ist die Datei chain.pem? Ist das chain.crt?
Dr.X
Es ist nicht die chain.crt, das ist für das eigentliche Zertifikat. Es ist die Liste der Zwischenzertifikate, auch bekannt als Zertifikatskette. Du brauchst es nicht unbedingt. Verwenden Sie einen SSL-Zertifizierungsprüfer, um herauszufinden, ob Sie ihn benötigen. In diesem Fall können Sie nach dem Namen Ihres Zertifikatsausstellers + dem Begriff "Kette" oder "Zwischenstufe" suchen, um die richtige Datei zu finden.
Nr.
4

Nachdem ich unter CentOS diesem Problem zum Opfer gefallen war, nachdem ich PHP auf PHP5.6 aktualisiert hatte, fand ich eine Lösung, die für mich funktionierte.

Holen Sie sich damit das richtige Verzeichnis für Ihre Zertifikate, das standardmäßig abgelegt werden soll

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

Verwenden Sie diese Option, um das Zertifikat abzurufen und an der Standardposition abzulegen, die im obigen Code angegeben ist

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

Hatte das gleiche SSL-Problem auf meinem Entwicklercomputer (PHP 7, XAMPP unter Windows) mit einem selbstsignierten Zertifikat, das versuchte, eine " https: // localhost / ..." - Datei zu öffnen . Offensichtlich hat die Root-Zertifikat-Assembly (cacert.pem) nicht funktioniert. Ich habe gerade manuell den Code aus der Datei apache server.crt-Datei in die heruntergeladene Datei cacert.pem kopiert und den Eintrag openssl.cafile = path / to / cacert.pem in php.ini ausgeführt

Kleiderbügel
quelle
2

Eine andere Sache, die Sie versuchen sollten, ist die Neuinstallation, ca-certificateswie hier beschrieben .

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

Sie können auch versuchen, das hier beschriebene Zertifikat der einen Site explizit zuzulassen, wie hier beschrieben (insbesondere, wenn die eine Site Ihr eigener Server ist und Sie die .pem-Datei bereits in Reichweite haben).

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

Nach dem Upgrade auf PHP 5.6 unter CentOS 6 trat genau dieser SO-Fehler auf, als ich versuchte, auf den Server selbst zuzugreifen, der über ein billiges Sicherheitszertifikat verfügt, das möglicherweise aktualisiert werden musste. Stattdessen installierte ich ein letsencrypt-Zertifikat und führte diese beiden obigen Schritte aus der Trick. Ich weiß nicht, warum der zweite Schritt notwendig war.


Nützliche Befehle

OpenSL-Version anzeigen:

# openssl version
OpenSSL 1.0.1e-fips 11 Feb 2013

Aktuelle Einstellungen für PHP cli ssl anzeigen:

# 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
Seite? ˅
quelle
1

In Bezug auf Fehler ähnlich wie

[11-May-2017 19:19:13 America / Chicago] PHP-Warnung: file_get_contents (): SSL-Vorgang mit Code 1 fehlgeschlagen. OpenSSL-Fehlermeldungen: Fehler: 14090086: SSL-Routinen: ssl3_get_server_certificate: Zertifikatüberprüfung fehlgeschlagen

Haben Sie die Berechtigungen des Zertifikats und der Verzeichnisse überprüft, auf die openssl verweist?

Du kannst das

var_dump(openssl_get_cert_locations());

Um etwas Ähnliches zu bekommen

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

Dieses Problem hat mich eine Weile frustriert, bis mir klar wurde, dass mein Ordner "certs" 700 Berechtigungen hatte, obwohl er 755 Berechtigungen hätte haben sollen. Denken Sie daran, dass dies nicht der Ordner für Schlüssel, sondern für Zertifikate ist. Ich empfehle, diesen Link über SSL-Berechtigungen zu lesen.

Einmal habe ich getan

chmod 755 certs

Das Problem wurde behoben, zumindest für mich.

Aleks
quelle
Yay! CHMOD war auch mein Problem ;-) Danke
RA.
0

Ich hatte das gleiche Problem für eine andere sichere Seite bei der Verwendung von wgetoderfile_get_contents . Viele Nachforschungen (einschließlich einiger Antworten auf diese Frage) führten zu einer einfachen Lösung - Installation von Curl und PHP-Curl - Wenn ich das richtig verstanden habe, hat Curl die Stammzertifizierungsstelle für Comodo, die das Problem behoben hat

Installieren Sie das Curl- und PHP-Curl-Addon und starten Sie Apache neu

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

Alles funktioniert jetzt.

Aubs
quelle