SSL-Verifizierung mit PHP schlägt fehlt (Fehler 14090086)

Wenn dich PHP mit dieser Fehlermeldung begrüßt, dann liegt es wohl daran, dass beim Abruf einer SSL-Ressource die Identität nicht verifiziert werden konnte. Und das ist auch gut so, denn der Sinn von SSL ist ja das Herstellen einer gesicherten Verbindung.
So sieht die Fehlermeldung bei Verwendung von file_get_contents(); aus. Aber auch andere Funktionen, mit denen man auf externe Ressourcen verweisen kann, werfen diesen Fehler, wie z.B. imagecreatefrompng();.

Die Ursache ist simpel: PHP kennt den Aussteller des Zertifikates für https://www.nickyreinert.de nicht und verweigert aus Sicherheitsgründen den Aufbau einer Verbindung. Wir müssen also entweder dafür sorgen, dass PHP dem Aussteller vertraut oder festlegen, dass PHP die Zertifikate gar nicht erst prüft.

Verifizierung des SSL Hosts unterdrücken

Das ist die quick’n’dirty Lösung. Zumindest file_get_contents(); kann mit Parametern gefüttert werden, die die Verifizierung der Ressource unterdrücken:

Wer auf eine eigene Ressource zurückgreift, z.B. im lokalen Netz oder zu Testzwecken, kann damit leben. Aus Sicherheitsgründen ist die Lösung allerdings nicht zu empfehlen. Außerdem funktioniert das nicht, wenn man Funktionen nutzt, bei denen diese Optionen nicht gesetzt werden können, wie z.B. imagecreatefromjpeg();

Die Zertifikatskette manuell einrichten

Man kommt also nicht darum, die saubere Lösung zu nutzen. Dazu muss man wissen, dass es in den allermeisten Fällen nicht um das eine Zertifikat geht, sondern um die Zertifikatskette. Diese beinhaltet auch die Zertifikate der Stellen, die dem infragekommenden Server https://www.nickyreinert.de das Zertifikat ausgestellt haben. Wenn PHP diese Stellen nicht kennt, geht es auch davon aus, dass die von dort ausgestellten Zertifikate nicht gültig sind.

 SSL Zertifikats-Kette mit den Intermediate Zertifikaten

SSL Zertifikats-Kette mit den Intermediate Zertifikaten

Um die Zertifikatskette zu erhalten, kannst du einen Service wie https://whatsmychaincert.com/ nutzen. Dieser liefert dir eine Datei mit der  kompletten Zertifikatskette.

PHP die Zertifikatskette mitteilen

Die Datei mit der Zertifikateskette gehört nun an einen Ort, den PHP erreichen kann. Dann musst du PHP noch mitteilen, dass es auch diese Zertifikatskette berücksichtigen soll. Auch das passiert über den Parameter, den ich oben schon angesprochen habe. Doch diesmal erlauben wir PHP, den SSL-Host zu verfizieren und verweisen auf die Zertifikatskette, die wir oben erstellt haben:

Geschafft. PHP sollte nun, zur Laufzeit, den SSL-Host überprüfen und dabei auf die Zertifikate zurückgreifen, die die Authentizität einwandfrei bestätigen.

Man kann den Verweis auch an anderer Stelle definieren. Die PHP-Funktion openssl_get_cert_locations(); teilt uns mit, wo PHP nach gültigen Zertifikaten sucht:

Hier fällt z.B. die Datei /Applications/XAMPP/xamppfiles/share/curl/curl-ca-bundle.crt auf. Diese wird in der php.ini mit dem Parameter

gesetzt. Auch in dieser Datei liegen eine Menge von Root- bzw. Intermediate-Zertifikaten. Mitunter macht es mehr Sinn, diese Einstellung in der php.ini zu nutzen, damit auch curl() darauf zurückgreifen kann.

Wenn du PHP-FPM benutzt, ist die Config-Datei etwas anders aufgebaut:

Zusammenfassung

Die SSL-Fehlermeldung hat ihren Sinn. PHP ist nicht in der Lage, die Authentizität des Servers zu überprüfen. Der korrekte Weg, das Problem zu beheben, ist das Zertifikat der entsprechenden Seite herunterzuladen, die Intermediate-Zertifikate und das Root-Zertifikat zu besorgen und alle Zertifikate im PEM-Format in eine Text-Datei zu packen.
Danach kannst du entweder auf die URL zugreifen und über den Stream-Kontext auf diese Datei mit der Zertifikats-Kette verweisen, oder du legst in den globalen PHP-Einstellungen fest, dass PHP diese Datei beim nächsten Mal berücksichtigen soll.