file_get_contents():SSL操作がコード1で失敗し、暗号を有効にできませんでした


188

私はサーバーで作成したPHPページからこの特定のRESTサービスにアクセスしようとしています。問題をこれら2つの行に絞り込みました。したがって、私のPHPページは次のようになります。

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

ページは2行目で終了し、次のエラーが発生します。

  • 警告:file_get_contents():SSL操作がコード1で失敗しました。OpenSSLエラーメッセージ:error:14090086:SSLルーチン:SSL3_GET_SERVER_CERTIFICATE:certificate verifyが... phpの2行目で失敗しました
    • 警告:file_get_contents():2行目の... phpで暗号を有効にできませんでした
    • 警告: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):ストリームを開けませんでした:2行目の... phpで操作が失敗しました

Gentooサーバーを使用しています。最近、PHPバージョン5.6にアップグレードしました。この問題が発生したのはアップグレード後です。

私のようなアドレスを使用してRESTサービスを交換するとき、私が見つかりましたhttps://www.google.com。私のページは問題なく動作します。

以前の試みでは“verify_peer”=>false、ここで説明するように、を設定し、それを引数としてfile_get_contentsに渡しました: file_get_contents ignoring verify_peer => false? しかし、筆者が指摘したように。違いはありませんでした。

サーバー管理者の1人に、php.iniファイルに次の行が存在するかどうかを尋ねました。

  • extension = php_openssl.dll
  • allow_url_fopen =オン

Gentooを使用しているため、ビルド時にopensslがコンパイルされると彼は言った。php.iniファイルでは設定されていません。

それallow_url_fopenが機能していることも確認しました。この問題の特殊な性質のため。助けになる情報がたくさん見つかりません。このようなものに出くわしたことがありますか?ありがとう。


カスペルスキーを使用している場合は、次を確認してください:stackoverflow.com/a/54791481/3549317
cespon

回答:


344

これは非常に役立つリンクでした。

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

PHP 5.6でopen sslに加えられた変更を説明する公式ドキュメントここから、falseに設定する必要があるもう1つのパラメーターを知りました: "verify_peer_name" => false

注:これは、セキュリティに非常に大きな影響を与えます。検証を無効にすると、MITM攻撃者が無効な証明書を使用してリクエストを盗聴できる可能性があります。ローカル開発でこれを行うと便利な場合がありますが、本番環境では他のアプローチを使用する必要があります。

だから私の作業コードは次のようになります:

<?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
これはSSL証明書に
違反し

8
@ hypery2kが指摘したように、検証を無効にするだけではいけません。sslを使用する目的を損なわない代替ソリューションについては、私の回答を参照してください。
elitechief21 2015

4
これは本当にすべきではありません。問題を回避するのではなく、実際に修正する必要があります。@ elitechief21からより良いソリューションを参照してください。
Jasper

5
APIに対してローカル環境からテストしている場合、これはイライラすることがあります。この場合、私は通常、検証を核にします。
HappyCoder 2015年

12
私がこれをしようとするときはいつもここに来るので、これは簡単にコピーして貼り付けるためのコードです:file_get_contents($url, false, stream_context_create(array('ssl' => array('verify_peer' => false, 'verify_peer_name' => false))));
laurent

154

検証をオフにするだけではいけません。むしろ、あなたは証明書バンドル、おそらくカールをダウンロードするべきですバンドルはそうするでしょう?

次に、それをWebサーバーに配置して、phpを実行するユーザーにファイルの読み取り権限を与えるだけです。次に、このコードはあなたのために働くはずです:

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

うまくいけば、アクセスしようとしているサイトのルート証明書はcurlバンドルに含まれています。そうでない場合でも、サイトのルート証明書を取得して証明書ファイルに書き込むまで、これは機能しません。


.crtファイルはどこから来たのですか?提供するcurl Webサイトにはリンクがありません。.pemのみです。
VEE

1
PEMファイルは同じでなければなりません。これが投稿された時点で、彼らのサイトには2つのバージョンの証明書バンドル、pemとcrtがあり、私は例としてcrtファイルを使用しただけです(当然、これは削除されるものです)。今後の参考のために、crtファイルは通常、名前がpemファイルに変更されます。これは、Windowsがファイルを証明書ファイルとして認識するように名前が変更されます。これは常にそうであるとは限りませんが、この場合はそうです。現在curlサイトにあるpemファイルを使用するように、サンプルを更新します
elitechief21

4
また、stream_context_set_default毎回file_get_contentsに渡す必要がない便利な関数もあります
Ken Koch

誰かがこれを機能させたことがありますか?この回答にリンクされているcacert.pemバンドルと、Comodo CAルート証明書(検証したい証明書のCAルート)を試してみましたが、常に失敗します。
zmippie 2017年

1
セキュリティの観点から:cafileストリームコンテキストオプションの使用方法の横に、許可された暗号を暗号ストリームコンテキストオプションで定義し、脆弱と呼ばれるSSLバージョンを禁止することが非常に重要になる場合があります。また、CRIME攻撃ベクトルを緩和するために、ストリームコンテキストオプションdisable_compressionをtrueに設定することをお勧めします。
Josef Glatz 2018

36

OpenSSLが自分のマシンにインストールされていることを確認してから、これをphp.iniに追加して、これを修正しました。

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

@AkhiあなたはそれをGoogleにあれば、いくつかのチュートリアルを見つけることができるはず
andlin

2
私は、IIS上でPHP 7を使用して同じ方法を使用し、ダウンロードcert.pemファイルをして設定しphp.ini、このように、それが働いた:openssl.cafile=D:\Tools\GnuWin32\bin\cacert.pem
デビッドRefoua

1
curl.haxx.se/docs/caextract.htmlからPEMファイルをダウンロードしました-Windowsで特定のgstatic.com URLを使用して問題を修正しました。
ジェイク

Centos 7では、curl.haxx.se / docs / caextract.htmlからPEMファイルをダウンロードできませんでした。メイン証明書とpkcs7を連結してバンドル証明書を作成し、サーバーに配置して、openssl.cafileパスを指定しました。正解と指示の場合は+1。
Arvind K.

バンドルを作成するときは、pkcsをpemファイルに変換してからメインの証明書にまとめることを忘れないでください
Arvind K.

22

次のように、curlを使用するカスタム関数を作成することで、この問題を回避できます。

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;

}

次に、httpsで始まるURLを呼び出すときfile_get_contents_curlfile_get_contents常に代わりに使用します。


これでうまくいきました。お疲れ様でした!
Nick Green

11

私のために働いて、私はPHP 5.6を使用しています。openssl拡張を有効にして、Googleマップapi verify_peerを呼び出すときにfalseにする必要があります以下のコードが私のために機能しています。

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

PHPのバージョンが5の場合は、ターミナルで次のコマンドを入力してcURLをインストールしてみてください。

sudo apt-get install php5-curl

9
これはとはまったく関係ありませんcURL
Andreas

2
php curlをインストールするのが正解です。私のMacシステムでは、私はポートを使用していて、コマンドは次のとおりです。sudo port install php70-curl
hailong


6

以下の手順に従って、この問題を修正します、

  1. 次のリンクからCA証明書をダウンロードします。https//curl.haxx.se/ca/cacert.pem
  2. php.iniを見つけて開きます
  3. 証明書をダウンロードした絶対パスを探してcurl.cainfo貼り付けます。curl.cainfo ="C:\wamp\htdocs\cert\cacert.pem"
  4. WAMP / XAMPP(Apacheサーバー)を再起動します。
  5. できます!

それが役に立てば幸い!!


これは安全ですか?私は簡単な解決策が大好きですが、ここにいくつかの情報がありませ
ん。–スイス

テストには
問題ありません

5

同じ問題に遭遇したのでこれに追加したかっただけで、どこにも見つからないことがありました(たとえば、cacert.pemファイルのダウンロード、php.iniでのcafileの設定など)。

NGINXを使用していて、SSL証明書に「中間証明書」が付属している場合は、中間証明書ファイルをメインの「mydomain.com.crt」ファイルと組み合わせる必要があります。Apacheには中間証明書に固有の設定がありますが、NGINXにはないため、通常の証明書と同じファイル内になければなりません。


4

このエラーの理由は、PHPに信頼できる認証局のリストがないためです。

PHP 5.6以降では、システムが信頼するCAを自動的にロードしようとします。その問題は修正できます。詳細については、http://php.net/manual/en/migration56.openssl.phpを参照してください。

PHP 5.5以前のバージョンでは、各リクエストコンテキストでCAバンドルを手動で指定する必要があるため、正しく設定するのが非常に難しく、コードにまき散らしたくないものです。それで、PHPバージョン5.6未満の場合、SSL検証が単に無効になるようにコードを決定しました。

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

これは私の問題を見つけるのに役立ちました。私はPHP 5.6を使用していますが、上記のリンクのようにcafileコンテキストオプションを使用して古いCAファイルを手動で指定した古いAPIクライアントライブラリを使用していました。これをAPIクライアントライブラリから削除すると、修正されました。おそらくPHPがOpenSSLの信頼できるバンドルの使用を開始した
Joe Lipson

4

XAMPPおよびOSX上のPHP 7で同じエラーが発生しました。

上記のhttps://stackoverflow.com/での回答は良いですが、問題は完全には解決しませんでした。file_get_contents()を再び機能させるには、完全な証明書チェーンを提供する必要がありました。それは私がそれをした方法です:

ルート/中間証明書を取得する

まず最初に、ルート中間証明書が何であるかを理解する必要がありました。

最も便利な方法は、おそらくssl-shopperのようなオンラインの証明書ツールです

そこで、3つの証明書が見つかりました。1つはサーバー証明書で、もう1つはチェーン証明書です(1つはルート、もう1つは明らかに中間です)。

私がする必要があるのは、両方をインターネットで検索することだけです。私の場合、これがルートです:

thawte DV SSL SHA256 CA

そして、それは彼のURL thawte.comにつながりますます。だから私はこの証明書をテキストファイルに入れて、中間者に対しても同じことをしました。できました。

ホスト証明書を取得する

次にしなければならないのは、サーバー証明書をダウンロードすることです。LinuxまたはOS Xでは、opensslで実行できます。

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

今、それらをすべて一緒にします

これらすべてを1つのファイルにマージします。(たぶん、それらを1つのフォルダーに入れるのが良いでしょう。私はそれらを1つのファイルにマージしただけです)。あなたはこのようにそれを行うことができます:

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

チェーンを見つける場所をPHPに指示する

この便利な関数openssl_get_cert_locations()は、PHPが証明書ファイルを探す場所を示します。そしてこのパラメータがあり、それはfile_get_contents()に証明書ファイルを探す場所を指示します。多分両方の方法がうまくいくでしょう。私はパラメータの方を好みました。(上記のソリューションと比較して)。

これが私の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));

それで全部です。file_get_contents()が再び機能します。CURLなしで、できればセキュリティ上の欠陥なしで。


ファイルはchain.pem何ですか?これchain.crtですか?
Dr.X 2018年

chain.crtではなく、実際の証明書用です。中間証明書(別名証明書チェーン)のリストです。必ずしも必要ではありません。SSL証明書チェッカーを使用して、必要かどうかを確認します。その場合は、証明書発行者の名前と「チェーン」または「中間」という用語を検索して、正しいファイルを見つけることができます。
2018年

4

phpをphp5.6に更新した後、centOSでこの問題の犠牲になった後、私はうまくいく解決策を見つけました。

これでデフォルトで配置されるあなたの証明書のための正しいディレクトリを取得します

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

次に、これを使用して証明書を取得し、上記のコードで見つかったデフォルトの場所に配置します

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

3

開発者のマシン(php 7、Windowsではxampp)で同じssl-problemがあり、「https:// localhost / ...」ファイルを開こうとする自己署名証明書があった。明らかに、ルート証明書アセンブリ(cacert.pem)は機能しませんでした。ダウンロードしたcacert.pemのapache server.crt-Fileからコードを手動でコピーし、php.iniのopenssl.cafile = path / to / cacert.pemエントリを作成しました


2

もう1つ試すことは、ここでca-certificates説明するように再インストールすることです。

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

ここで説明するように、問題のあるサイトの証明書を明示的に許可することも試みます(特に、1つのサイトが独自のサーバーであり、すでに.pemが届いている場合)。

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

CentOS 6のPHP 5.6にアップグレードした後、更新する必要があるかもしれない安価なセキュリティ証明書を持つサーバー自体にアクセスしようとした後、この正確なSOエラーに遭遇しましたが、代わりにletsencrypt証明書をインストールし、上記の2つの手順で実行しましたトリック。なぜ第二のステップが必要だったのか分かりません。


便利なコマンド

opensslバージョンを表示:

# openssl version
OpenSSL 1.0.1e-fips 11 Feb 2013

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

同様のエラーについて

[2017年5月11日19:19:13アメリカ/シカゴ] PHP警告:file_get_contents():SSL操作がコード1で失敗しました。OpenSSLエラーメッセージ:error:14090086:SSLルーチン:ssl3_get_server_certificate:certificate検証に失敗しました

opensslが参照する証明書とディレクトリの権限を確認しましたか?

あなたはこれを行うことができます

var_dump(openssl_get_cert_locations());

これに似たものを得るために

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

この問題は、「certs」フォルダに700のアクセス許可があり、755のアクセス許可が必要であることに気付くまで、しばらくイライラしました。これは鍵のフォルダではなく、証明書であることを忘れないでください。私はこのsslパーミッションに関するこのリンクを読むことを勧めます。

やったら

chmod 755 certs

少なくともとにかく、問題は修正されました。


わーい!CHMODも私の問題でした;-)ありがとう
RA。

0

wgetまたはを使用すると、別の安全なページで同じ問題が発生しましたfile_get_contents。多くの調査(この質問に対するいくつかの回答を含む)により、シンプルな解決策が得られました-CurlとPHP-Curlのインストール-私が正しく理解していれば、CurlにはComodoのルートCAがあり、問題を解決しました

CurlおよびPHP-Curlアドオンをインストールして、Apacheを再起動します

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

現在はすべて機能しています。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.