file_get_contents (): Operasi SSL gagal dengan kode 1, Gagal mengaktifkan kripto

188

Saya sudah mencoba mengakses layanan REST khusus ini dari halaman PHP yang saya buat di server kami. Saya mempersempit masalahnya menjadi dua baris ini. Jadi halaman PHP saya terlihat seperti ini:

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

Halaman mati pada baris 2 dengan kesalahan berikut:

  • Peringatan: file_get_contents (): Operasi SSL gagal dengan kode 1. Pesan kesalahan OpenSSL: kesalahan: 14090086: rutinitas SSL: SSL3_GET_SERVER_CERTIFICATE: verifikasi sertifikat gagal di ... php on line 2
    • Peringatan: file_get_contents (): Gagal mengaktifkan crypto di ... php on line 2
    • Peringatan: 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): gagal membuka aliran: operasi gagal di ... php on line 2

Kami menggunakan server Gentoo. Kami baru-baru ini ditingkatkan ke PHP versi 5.6. Itu setelah pemutakhiran ketika masalah ini muncul.

Saya menemukan ketika saya mengganti layanan REST dengan alamat seperti https://www.google.com; halaman saya berfungsi dengan baik.

Dalam upaya sebelumnya saya menetapkan “verify_peer”=>false, dan meneruskannya sebagai argumen ke file_get_contents, seperti yang dijelaskan di sini: file_get_contents mengabaikan Verify_peer => false? Tapi seperti yang dicatat penulis; tidak ada bedanya.

Saya telah bertanya kepada salah satu administrator server kami apakah baris-baris ini dalam file php.ini kami ada:

  • extension = php_openssl.dll
  • allow_url_fopen = Hidup

Dia memberi tahu saya bahwa karena kita menggunakan Gentoo, openssl dikompilasi ketika kita membangun; dan itu tidak diatur dalam file php.ini.

Saya juga mengkonfirmasi bahwa allow_url_fopenitu berfungsi. Karena sifat khusus masalah ini; Saya tidak menemukan banyak informasi untuk bantuan. Apakah ada di antara Anda yang menemukan sesuatu seperti ini? Terima kasih.

Joe
sumber
Jika Anda menggunakan Kaspersky, periksa ini: stackoverflow.com/a/54791481/3549317
cespon

Jawaban:

344

Ini adalah tautan yang sangat bermanfaat untuk ditemukan:

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

Dokumen resmi yang menjelaskan perubahan yang dibuat untuk membuka ssl di PHP 5.6 Dari sini saya mempelajari satu parameter lagi yang seharusnya saya atur menjadi false: "memverifikasi_peer_name" => false

Catatan: Ini memiliki implikasi keamanan yang sangat signifikan. Menonaktifkan verifikasi berpotensi memungkinkan penyerang MITM menggunakan sertifikat yang tidak valid untuk menguping permintaan. Meskipun mungkin bermanfaat untuk melakukan hal ini dalam pengembangan lokal, pendekatan lain harus digunakan dalam produksi.

Jadi kode kerja saya terlihat seperti ini:

<?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
sumber
122
ini mematahkan sertifikasi SSL dan merupakan celah keamanan
hypery2k
8
Seperti yang ditunjukkan oleh @ hypery2k, Anda seharusnya tidak menonaktifkan verifikasi. Lihat jawaban saya untuk solusi alternatif yang tidak mengalahkan tujuan menggunakan ssl.
elitechief21
4
Ini benar-benar tidak boleh dilakukan. Daripada mengesampingkan masalah Anda harus benar-benar memperbaikinya. Lihat solusi yang lebih baik dari @ elitechief21.
Jasper
5
Ini bisa membuat frustasi jika Anda menguji dari lingkungan lokal terhadap api. Dalam hal ini saya biasanya membatalkan verifikasi.
HappyCoder
12
Karena saya selalu datang ke sini ketika saya mencoba melakukan ini, di sini adalah kode untuk dengan mudah copy dan paste:file_get_contents($url, false, stream_context_create(array('ssl' => array('verify_peer' => false, 'verify_peer_name' => false))));
laurent
154

Anda tidak seharusnya mematikan verifikasi saja. Alih-alih Anda harus mengunduh bundel sertifikat, mungkin bundel ikal akan melakukannya?

Maka Anda hanya perlu meletakkannya di server web Anda, memberikan pengguna yang menjalankan izin php untuk membaca file. Maka kode ini akan bekerja untuk Anda:

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

Mudah-mudahan, sertifikat root dari situs yang Anda coba akses ada di bundel ikal. Jika tidak, ini masih tidak akan berfungsi sampai Anda mendapatkan sertifikat root dari situs dan memasukkannya ke file sertifikat Anda.

elitechief21
sumber
Di mana file .crt berasal? Tidak ada tautan di situs web curl yang Anda berikan hanya memiliki .pem.
vee
1
File pem harus sama. Pada saat ini diposting, mereka memiliki dua versi bundel sertifikat di situs mereka, pem dan crt dan saya hanya menggunakan file crt untuk contoh saya (tentu saja itu yang akan mereka hapus). Untuk referensi di masa mendatang, file crt biasanya berganti nama menjadi file pem, yang diubah namanya agar windows mengenali file tersebut sebagai file sertifikat. Ini tidak selalu menjadi masalah, tetapi dalam kasus ini. Saya akan memperbarui contoh saya sehingga menggunakan file pem saat ini di situs curl
elitechief21
4
Ada juga fungsi bermanfaat stream_context_set_defaultyang dapat digunakan sehingga Anda tidak harus meneruskannya ke file_get_contents setiap kali
Ken Koch
Apakah ada yang pernah membuat ini bekerja? Saya mencoba dengan bundel cacert.pem yang ditautkan dalam jawaban ini, dan juga dengan sertifikat Comodo CA Root (yang merupakan akar CA untuk sertifikat yang ingin saya verifikasi), tetapi selalu gagal.
zmippie
1
Dari perspektif keamanan: di samping penggunaan opsi konteks aliran kafetaria, bisa juga sangat penting untuk mendefinisikan sandi yang diizinkan dalam opsi konteks aliran sandi dan melarang versi SSL yang dikenal rentan. Juga menyetel opsi konteks aliran disable_compression ke true direkomendasikan untuk mengurangi vektor serangan CRIME.
Josef Glatz
36

Saya memperbaiki ini dengan memastikan bahwa OpenSSL telah diinstal pada mesin saya dan kemudian menambahkan ini ke php.ini saya:

openssl.cafile=/usr/local/etc/openssl/cert.pem
andlin
sumber
@ Akhi Anda harus dapat menemukan beberapa tutorial jika Anda Google itu
andlin
2
Saya menggunakan metode yang sama menggunakan PHP 7 pada IIS, mengunduh cert.pemfile dan mengatur yang php.iniseperti ini, dan itu berhasil:openssl.cafile=D:\Tools\GnuWin32\bin\cacert.pem
David Refoua
1
Saya mengunduh file PEM dari curl.haxx.se/docs/caextract.html - memperbaiki masalah saya di Windows dengan URL gstatic.com tertentu.
Jake
Mengunduh file PEM dari curl.haxx.se/docs/caextract.html tidak berfungsi untuk saya di Centos 7. Saya membuat sertifikat bundel dengan menggabungkan sertifikat utama dan pkcs7 dan meletakkannya di server lalu menentukan path openssl.cafile. +1 untuk jawaban dan arahan yang benar.
Arvind K.
Saat membuat bundel jangan lupa untuk mengonversi pkcs ke file pem sebelum menyimpulkannya menjadi sertifikasi utama
Arvind K.
22

Anda dapat mengatasi masalah ini dengan menulis fungsi kustom yang menggunakan curl, seperti pada:

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;

}

Maka gunakan saja file_get_contents_curlalih-alih file_get_contentssetiap kali Anda memanggil url yang dimulai dengan https.

Ben Shoval
sumber
Ini berhasil untuk saya. Kerja bagus dan terima kasih!
Nick Green
11

Bekerja untuk saya, saya menggunakan PHP 5.6. ekstensi openssl harus diaktifkan dan saat memanggil google map api verifikasi_peer buat 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;
?>
Dipti
sumber
10

Jika versi PHP Anda 5, coba instal cURL dengan mengetik perintah berikut di terminal:

sudo apt-get install php5-curl
ARUNBALAN NV
sumber
9
Ini sama sekali tidak ada hubungannya cURL.
Andreas
2
Menginstal php curl seharusnya menjadi jawaban yang benar! Untuk sistem Mac saya, saya menggunakan port, dan perintahnya adalah:sudo port install php70-curl
hailong
6

mengikuti langkah-langkah di bawah ini akan memperbaiki masalah ini,

  1. Unduh Sertifikat CA dari tautan ini: https://curl.haxx.se/ca/cacert.pem
  2. Temukan dan buka php.ini
  3. Cari curl.cainfodan tempelkan path absolut tempat Anda mengunduh Sertifikat.curl.cainfo ="C:\wamp\htdocs\cert\cacert.pem"
  4. Mulai ulang WAMP / XAMPP (server apache).
  5. Berhasil!

berharap itu bisa membantu !!

shakee93
sumber
apakah ini aman Saya suka solusi mudah tetapi saya kehilangan beberapa informasi di sini ..
swisswiss
untuk pengujian ok
Geomorillo
5

Hanya ingin menambahkan ini karena saya mengalami masalah yang sama dan tidak ada yang bisa saya temukan di mana saja akan berfungsi (misalnya mengunduh file cacert.pem, mengatur cafile di php.ini dll.)

Jika Anda menggunakan NGINX dan sertifikat SSL Anda dilengkapi dengan "sertifikat perantara", Anda harus menggabungkan file sertifikat perantara dengan file "mydomain.com.crt" utama Anda dan harus berfungsi. Apache memiliki pengaturan khusus untuk sertifikat perantara, tetapi NGINX tidak melakukannya sehingga harus berada dalam file yang sama dengan sertifikat biasa Anda.

SlickTheNick
sumber
4

Alasan untuk kesalahan ini adalah PHP tidak memiliki daftar otoritas sertifikat tepercaya.

PHP 5.6 dan yang lebih baru mencoba memuat CA yang dipercaya oleh sistem secara otomatis. Masalah dengan itu bisa diperbaiki. Lihat http://php.net/manual/en/migration56.openssl.php untuk informasi lebih lanjut.

PHP 5.5 dan sebelumnya benar - benar sulit untuk dipasang dengan benar karena Anda secara manual harus menentukan bundel CA di setiap konteks permintaan, hal yang tidak ingin Anda taburkan di sekitar kode Anda. Jadi saya memutuskan untuk kode saya bahwa untuk versi PHP <5.6, verifikasi SSL hanya dinonaktifkan:

$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
sumber
Ini membantu saya menemukan masalah saya. Meskipun saya menggunakan PHP 5.6, saya menggunakan pustaka klien api yang sudah usang yang secara manual menentukan file CA lama menggunakan opsi konteks kaforis sesuai tautan Anda di atas. Menghapus itu dari pustaka klien api memperbaikinya untuk saya. Mungkin PHP mulai menggunakan bundel tepercaya OpenSSLs
Joe Lipson
4

Mengalami kesalahan yang sama dengan PHP 7 pada XAMPP dan OSX.

Jawaban yang disebutkan di atas dalam https://stackoverflow.com/ baik, tetapi tidak sepenuhnya menyelesaikan masalah bagi saya. Saya harus memberikan rantai sertifikat lengkap untuk membuat file_get_contents () berfungsi lagi. Begitulah cara saya melakukannya:

Dapatkan sertifikat root / perantara

Pertama-tama saya harus mencari tahu apa akarnya dan sertifikat perantara.

Cara paling nyaman adalah mungkin alat sertifikat online seperti ssl-shopper

Di sana saya menemukan tiga sertifikat, satu sertifikat server dan dua sertifikat berantai (satu adalah root, yang lain tampaknya perantara).

Yang perlu saya lakukan hanyalah mencari internet untuk mereka berdua. Dalam kasus saya, ini adalah root:

thawte DV SSL SHA256 CA

Dan itu mengarah ke url thawte.com-nya . Jadi saya hanya memasukkan sertifikat ini ke dalam file teks dan melakukan hal yang sama untuk perantara. Selesai

Dapatkan sertifikat host

Hal berikutnya yang harus saya lakukan adalah mengunduh cert server saya. Di Linux atau OS X dapat dilakukan dengan openssl:

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

Sekarang kumpulkan mereka semua

Sekarang gabungkan semuanya menjadi satu file. (Mungkin ada baiknya untuk menempatkannya dalam satu folder, saya hanya menggabungkannya menjadi satu file). Anda dapat melakukannya seperti ini:

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

beri tahu PHP di mana menemukan rantai

Ada fungsi praktis ini openssl_get_cert_locations () yang akan memberi tahu Anda, tempat PHP mencari file cert. Dan ada parameter ini, yang akan memberi tahu file_get_contents () di mana harus mencari file cert. Mungkin kedua cara itu akan berhasil. Saya lebih suka cara parameter. (Dibandingkan dengan solusi yang disebutkan di atas).

Jadi sekarang ini adalah PHP-Code saya

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

Itu saja. file_get_contents () berfungsi kembali. Tanpa CURL dan mudah-mudahan tanpa cacat keamanan.

no
sumber
Apa file-nya chain.pem? Apakah ini chain.crt?
Dr.X
Ini bukan chain.crt, itu untuk sertifikat yang sebenarnya. Ini daftar jika sertifikat menengah, alias rantai sertifikat. Anda tidak perlu membutuhkannya. Gunakan pemeriksa sertifikat SSL untuk mencari tahu apakah Anda membutuhkannya. Jika demikian, Anda dapat mencari nama penerbit sertifikat Anda + istilah "rantai" atau "perantara" untuk menemukan file yang benar.
nr
4

Setelah menjadi korban masalah ini pada centOS setelah memperbarui php ke php5.6 saya menemukan solusi yang bekerja untuk saya.

Dapatkan direktori yang benar untuk sertifikat Anda untuk ditempatkan secara default dengan ini

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

Kemudian gunakan ini untuk mendapatkan sertifikat dan meletakkannya di lokasi default yang ditemukan dari kode di atas

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

Memiliki masalah ssl yang sama pada mesin pengembang saya (php 7, xampp pada windows) dengan sertifikat yang ditandatangani sendiri mencoba membuka " https: // localhost / ..." - file. Jelas rakitan-sertifikat-root (cacert.pem) tidak berfungsi. Saya baru saja menyalin kode secara manual dari apache server.crt-File di cacert.pem yang diunduh dan melakukan entri openssl.cafile = path / to / cacert.pem di php.ini

gantungan baju
sumber
2

Hal lain yang harus dicoba adalah menginstal ulang ca-certificatesseperti yang dijelaskan di sini .

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

Dan hal lain yang harus dicoba adalah secara eksplisit mengizinkan sertifikat satu situs yang dimaksud seperti yang dijelaskan di sini (terutama jika satu situs adalah server Anda sendiri dan Anda sudah memiliki .pem dalam jangkauan).

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

Saya mengalami kesalahan SO yang tepat ini setelah memutakhirkan ke PHP 5.6 pada CentOS 6 mencoba mengakses server itu sendiri yang memiliki sertifikat keamanan keselamatan yang lebih rendah yang mungkin perlu diperbarui, tetapi sebaliknya saya menginstal sertifikat allowencrypt dan dengan dua langkah di atas itu melakukannya Trik-nya. Saya tidak tahu mengapa langkah kedua diperlukan.


Perintah yang Berguna

Lihat versi openssl:

# openssl version
OpenSSL 1.0.1e-fips 11 Feb 2013

Lihat pengaturan PHP cli ssl saat ini:

# 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
situs
sumber
1

Mengenai kesalahan mirip dengan

[11-May-2017 19:19:13 America / Chicago] Peringatan PHP: file_get_contents (): Operasi SSL gagal dengan kode 1. Pesan kesalahan OpenSSL: kesalahan: 14090086: rutinitas SSL: ssl3_get_server_certificate: sertifikat diverifikasi gagal

Sudahkah Anda memeriksa izin sertifikat dan direktori yang dirujuk oleh openssl?

Kamu bisa melakukan ini

var_dump(openssl_get_cert_locations());

Untuk mendapatkan sesuatu yang mirip dengan ini

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

Masalah ini membuat saya frustrasi untuk sementara waktu, sampai saya menyadari bahwa folder "sertifikat" saya memiliki 700 izin, padahal seharusnya 755 izin. Ingat, ini bukan folder untuk kunci tetapi sertifikat. Saya sarankan membaca tautan ini pada izin ssl.

Pernah saya lakukan

chmod 755 certs

Masalahnya sudah diperbaiki, setidaknya untuk saya.

Aleks
sumber
Yay! CHMOD juga masalah saya ;-) Terima kasih
RA.
0

Saya memiliki masalah yang sama untuk halaman aman lain saat menggunakan wgetatau file_get_contents. Banyak penelitian (termasuk beberapa tanggapan pada pertanyaan ini) menghasilkan solusi sederhana - menginstal Curl dan PHP-Curl - Jika saya mengerti dengan benar, Curl memiliki Root CA untuk Comodo yang menyelesaikan masalah

Instal Curl dan addon PHP-Curl, kemudian restart Apache

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

Semua sudah berfungsi.

Aubs
sumber