web-dev-qa-db-fra.com

file_get_contents (): l'opération SSL a échoué avec le code 1, impossible d'activer le cryptage

J'ai essayé d'accéder à ce service REST particulier à partir d'une page PHP que j'ai créée sur notre serveur. J'ai réduit le problème à ces deux lignes. Donc, ma page PHP ressemble à ceci:

<?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 page meurt sur la ligne 2 avec les erreurs suivantes:

  • Avertissement: file_get_contents (): l'opération SSL a échoué avec le code 1. Messages d'erreur OpenSSL: erreur: 14090086: routines SSL: SSL3_GET_SERVER_CERTIFICATE: la vérification du certificat a échoué dans ... php sur la ligne 2
    • Avertissement: file_get_contents (): Impossible d'activer le cryptage dans ... php on line 2
    • Attention: 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): impossible d'ouvrir le flux: l'opération a échoué dans ... php sur la ligne 2

Nous utilisons un serveur Gentoo. Nous avons récemment effectué une mise à niveau vers PHP version 5.6. C'était après la mise à niveau lorsque ce problème est apparu.

J'ai trouvé quand je remplace le service REST par une adresse comme https://www.google.com; ma page fonctionne très bien.

Lors d'une tentative précédente, j'ai défini “verify_peer”=>false et l'ai transmis en tant qu'argument à file_get_contents, comme décrit ci-après: file_get_contents en ignorant verify_peer => false? Mais comme l'a noté l'auteur; cela ne faisait aucune différence.

J'ai demandé à l'un de nos administrateurs de serveur si ces lignes dans notre fichier php.ini existaient:

  • extension = php_openssl.dll
  • allow_url_fopen = On

Il m’a dit que puisque nous sommes sur Gentoo, openssl est compilé lorsque nous construisons; et cela n’est pas défini dans le fichier php.ini.

J'ai également confirmé que allow_url_fopen fonctionne. En raison de la nature spécialisée de ce problème; Je ne trouve pas beaucoup d’informations pour obtenir de l’aide. L'un de vous a-t-il rencontré quelque chose comme ça? Merci.

157
Joe

C'était un lien extrêmement utile à trouver:

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

Un document officiel décrivant les modifications apportées pour ouvrir ssl dans PHP 5.6 À partir de là, j'ai appris l'existence d'un paramètre de plus que j'aurais dû mettre à false: "verify_peer_name" => false

Remarque: Cela a des implications très importantes pour la sécurité. La désactivation de la vérification permet potentiellement à attaquant MITM d'utiliser un certificat non valide pour écouter les requêtes. Bien que cela puisse être utile dans le développement local, d’autres approches devraient être utilisées dans la production.

Donc, mon code de travail ressemble à ceci:

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

Vous ne devriez pas simplement désactiver la vérification. Vous devriez plutôt télécharger un paquet de certificats, peut-être que le paquet curl fera?

Ensuite, il vous suffit de le mettre sur votre serveur Web, en donnant à l'utilisateur qui exécute l'autorisation php de lire le fichier. Alors ce code devrait fonctionner pour vous:

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

Espérons que le certificat racine du site auquel vous essayez d'accéder se trouve dans le paquet curl. Si ce n'est pas le cas, cela ne fonctionnera toujours pas jusqu'à ce que vous obteniez le certificat racine du site et que vous le placiez dans votre fichier de certificat.

140
elitechief21

J'ai résolu ce problème en m'assurant qu'OpenSSL était installé sur ma machine, puis en l'ajoutant à mon fichier php.ini:

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

Vous pouvez contourner ce problème en écrivant une fonction personnalisée qui utilise curl, comme dans:

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;

}

Ensuite, utilisez simplement file_get_contents_curl au lieu de file_get_contents chaque fois que vous appelez une URL commençant par https.

14
Ben Shoval

Si votre version PHP est la version 5, essayez d'installer cURL en tapant la commande suivante dans le terminal:

Sudo apt-get install php5-curl
11
ARUNBALAN NV

Vous devez définir la variable d’environnement SSL_CERT_FILE sur le chemin du fichier PEM du certificat SSL téléchargé à partir du lien suivant: http://curl.haxx.se/ca/cacert.pem .

Il m'a fallu beaucoup de temps pour comprendre cela.

7
Kshitij Mittal

les étapes ci-dessous résoudront ce problème,

  1. Téléchargez le certificat de CA à partir de ce lien: https://curl.haxx.se/ca/cacert.pem
  2. Trouvez et ouvrez php.ini
  3. Cherchez curl.cainfo et collez le chemin absolu où vous avez téléchargé le certificat. curl.cainfo ="C:\wamp\htdocs\cert\cacert.pem"
  4. Redémarrez WAMP/XAMPP (serveur Apache).
  5. Ça marche!

j'espère que ça t'as aidé !!

6
shakee93

Je voulais juste ajouter quelque chose à cela puisque je rencontrais le même problème et que rien que je ne pourrais trouver n’importe où ne fonctionnerait (par exemple télécharger le fichier cacert.pem, régler cafile dans php.ini, etc.)

Si vous utilisez NGINX et que votre certificat SSL est livré avec un "certificat intermédiaire", vous devez combiner le fichier de certification intermédiaire avec votre fichier principal "mydomain.com.crt" et cela devrait fonctionner. Apache a un paramètre spécifique pour les certificats intermédiaires, mais NGINX ne l’a pas, il doit donc se trouver dans le même fichier que votre certificat habituel.

5
SlickTheNick

Travaillant pour moi, j’utilise PHP 5.6. L’extension openssl doit être activée et tout en appelant google map api verify_peer make false, le code ci-dessous fonctionne pour moi.

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

 $response = file_get_contents("https://maps.googleapis.com/maps/api/geocode     /json?latlng=" . $latitude . "," . $longitude . "&sensor=false&key=" . Yii::$app->params['GOOGLE_API_KEY'], false, stream_context_create($arrContextOptions));

echo $response; ?>
5
Dipti

Avait la même erreur avec PHP 7 sur XAMPP et OSX.

La réponse mentionnée ci-dessus dans https://stackoverflow.com/ est bonne, mais elle n'a pas complètement résolu le problème. Je devais fournir la chaîne de certificats complète pour que file_get_contents () fonctionne à nouveau. C'est comme ça que je l'ai fait:

Obtenir le certificat racine/intermédiaire

Tout d'abord, je devais déterminer quelle était la racine et le certificat intermédiaire.

Le moyen le plus pratique est peut-être un outil de certification en ligne comme le ssl-shopper

Là, j'ai trouvé trois certificats, un certificat de serveur et deux certificats de chaîne (l'un est la racine, l'autre, apparemment, intermédiaire).

Tout ce que j'ai à faire est de simplement chercher sur Internet pour les deux. Dans mon cas, c'est la racine:

thawte DV SSL SHA256 CA

Et cela mène à son URL thawte.com . Donc, je viens de mettre ce cert dans un fichier texte et fait de même pour les intermédiaires. Terminé.

Obtenir le certificat d'hôte

La prochaine chose que je devais faire est de télécharger mon certificat de serveur. Sous Linux ou OS X, cela peut être fait avec openssl:

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

Maintenant rassemblez-les tous

Maintenant, il suffit de les fusionner dans un seul fichier. (Peut-être que c'est bien de simplement les mettre dans un dossier, je les ai simplement fusionnées dans un seul fichier). Vous pouvez le faire comme ça:

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

dire à PHP où trouver la chaîne

Il y a cette fonction pratique openssl_get_cert_locations () qui vous dira où PHP recherche des fichiers de certificat. Et il y a ce paramètre, qui indiquera à file_get_contents () où chercher les fichiers de cert. Peut-être que les deux manières fonctionneront. Je préférais le paramètre way. (Par rapport à la solution mentionnée ci-dessus).

C'est donc maintenant mon code 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));

C'est tout. file_get_contents () fonctionne à nouveau. Sans CURL et, espérons-le, sans faille de sécurité.

4
n.r.

La raison de cette erreur est que PHP ne dispose pas d'une liste d'autorités de certification approuvées.

PHP 5.6 et versions ultérieures essaient de charger automatiquement les autorités de certification approuvées par le système. Les problèmes avec cela peuvent être corrigés. Voir http://php.net/manual/en/migration56.openssl.php pour plus d'informations.

PHP 5.5 et les versions antérieures sont vraiment difficiles à configurer correctement car vous devez spécifier manuellement le groupe d'AC dans chaque contexte de requête, ce que vous ne voulez pas saupoudrer autour de votre code. J'ai donc décidé pour mon code que pour PHP versions <5.6, la vérification SSL est simplement désactivée:

$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);
}
4
cweiske

Avait le même problème SSL sur ma machine de développeur (PHP 7, xampp sur Windows) avec un certificat auto-signé en essayant de fopen un " https: // localhost / ..." -file. De toute évidence, le certificat-racine-Assembly (cacert.pem) ne fonctionnait pas. Je viens de copier manuellement le code du serveur Apache server.crt dans le fichier cacert.pem téléchargé et de créer l'entrée openssl.cafile = chemin/vers/cacert.pem dans le fichier php.ini.

3
hangerer

Après être tombé victime de ce problème sur centOS après la mise à jour de php en php5.6, j'ai trouvé une solution qui fonctionnait pour moi.

Obtenez le bon répertoire pour que vos certificats soient placés par défaut avec cette

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

Ensuite, utilisez ceci pour obtenir le certificat et le placer à l'emplacement par défaut trouvé dans le code ci-dessus

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

En ce qui concerne les erreurs similaires à

[11-mai-2017 19:19:13 Amérique/Chicago] PHP Avertissement: fichier_get_contents (): l'opération SSL a échoué avec le code 1. Messages d'erreur OpenSSL: erreur: 14090086: routines SSL: ssl3_get_server_certificate: certificat de vérification échoué

Avez-vous vérifié les autorisations du cert et des répertoires référencés par openssl?

Tu peux le faire

var_dump(openssl_get_cert_locations());

Pour obtenir quelque chose de semblable à ceci

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

Ce problème m'a frustré pendant un certain temps, jusqu'à ce que je réalise que mon dossier "certificats" avait 700 autorisations, alors qu'il aurait dû avoir 755 autorisations. N'oubliez pas que ce n'est pas le dossier des clés, mais des certificats. Je recommande de lire ceci ce lien sur les autorisations ssl.

Une fois que j'ai fait

chmod 755 certs

Le problème a été résolu, du moins pour moi de toute façon.

1
Aleks

Une autre chose à essayer est de réinstaller ca-certificates comme détaillé ici .

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

Et une autre chose à essayer est d’autoriser explicitement le certificat du site en question comme décrit ici (surtout si le site est votre propre serveur et que vous avez déjà le fichier .pem à portée de main).

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

Je rencontrais cette erreur exacte SO après la mise à niveau vers PHP 5.6 sur CentOS 6 en essayant d’accéder au serveur lui-même, qui possède un certificat installé un certificat de letencrypt et avec ces deux étapes ci-dessus fait le tour. Je ne sais pas pourquoi la deuxième étape était nécessaire.


Commandes utiles

Voir la version openssl:

# openssl version
OpenSSL 1.0.1e-fips 11 Feb 2013

Affichez les paramètres actuels de 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
site

J'ai eu le même problème pour une autre page sécurisée lorsque j'utilisais wget ou file_get_contents. De nombreuses recherches (y compris certaines des réponses à cette question) ont abouti à une solution simple - installer Curl et PHP-Curl - Si j'ai bien compris, Curl dispose de l'autorité de certification racine de Comodo qui a résolu le problème.

Installez le complément Curl et PHP-Curl, puis redémarrez Apache.

Sudo apt-get install curl
Sudo apt-get install php-curl
Sudo /etc/init.d/Apache2 reload

Tous travaillent maintenant.

0
Aubs