file_get_contents():SSL操作失败,代码为1,无法启用加密

问题描述 投票:152回答:16

我一直在尝试从我在服务器上创建的PHP页面访问这个特定的REST服务。我将问题缩小到这两行。所以我的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错误消息:错误:14090086:SSL例程:SSL3_GET_SERVER_CERTIFICATE:证书验证失败...第2行的php 警告: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版。升级后出现此问题。

当我用https://www.google.com这样的地址替换REST服务时,我发现了我的页面工作正常。

在之前的尝试中,我设置了“verify_peer”=>false,并将其作为参数传递给file_get_contents,如下所述:file_get_contents ignoring verify_peer=>false?但是像作者所指出的那样;它没有任何区别。

我问过我们的服务器管理员是否存在php.ini文件中的这些行:

  • 延长= php_openssl.dll
  • allow_url_fopen =开

他告诉我,因为我们在Gentoo上,openssl是在我们构建时编译的;并且它没有在php.ini文件中设置。

我也确认allow_url_fopen正在工作。由于这个问题的专业性;我没有找到很多帮助信息。有没有人遇到过这样的事情?谢谢。

php rest ssl file-get-contents
16个回答
270
投票

这是一个非常有用的链接,可以找到:

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

一个官方文档描述了在PHP 5.6中打开ssl所做的更改从这里我学到了另一个我应该设置为false的参数:“verify_peer_name”=> false

注意:这具有非常重要的安全隐患。禁用验证可能允许MITM attacker使用无效证书来窃听请求。虽然在本地开发中执行此操作可能很有用,但在生产中应使用其他方法。

所以我的工作代码如下所示:

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

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

4
投票

在XAMPP和OSX上与PHP 7有相同的错误。

https://stackoverflow.com/上面提到的答案是好的,但它并没有完全解决我的问题。我必须提供完整的证书链才能使file_get_contents()再次运行。这就是我做到的方式:

获取root /中间证书

首先,我必须弄清楚根和中间证书是什么。

最方便的方法可能是像ssl-shopper这样的在线证书工具

在那里,我发现了三个证书,一个服务器证书和两个链证书(一个是根,另一个是中间人)。

我需要做的只是在互联网上搜索它们。就我而言,这是根:

解冻DV SSL SHA256 CA.

它导致他的网址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

现在把它们全部带到一起

现在只需将它们合并到一个文件中即可。 (也许将它们放入一个文件夹是很好的,我只是将它们合并到一个文件中)。你可以这样做:

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在哪里寻找cert文件。并且有这个参数,它将告诉file_get_contents()在哪里查找cert文件。也许两种方式都可行。我更喜欢参数方式。 (与上述解决方案相比)。

所以现在这是我的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,希望没有安全漏洞。


3
投票

在我的开发人员机器(php 7,Windows上的xampp)上有一个自签名证书试图打开“https://localhost/ ...”文件的同一个ssl问题。显然,root-certificate-assembly(cacert.pem)不起作用。我只是手动复制了下载的cacert.pem中的apache server.crt-File中的代码,并在php.ini中执行了openssl.cafile = path / to / cacert.pem条目


2
投票

在将php更新到php5.6之后,在centOS上成为这个问题的受害者之后,我找到了一个适合我的解决方案。

默认情况下,获取正确的证书目录

php -r 'print_r(openssl_get_cert_locations());' | grep '\[default_cert_file\]' | awk '{print $3}'

然后使用它来获取证书并将其放在上面代码中找到的默认位置

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

1
投票

关于类似的错误

[2017年5月11日19:19:13 America / Chicago] PHP警告:file_get_contents():SSL操作失败,代码为1. OpenSSL错误消息:错误:14090086:SSL例程:ssl3_get_server_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个权限时。请记住,这不是密钥的文件夹,而是证书。我建议阅读这个this link on ssl permissions.

有一次我做了

chmod 755 certs

问题是固定的,至少对我来说是这样。


0
投票

使用wgetfile_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

现在都在工作。


0
投票

另一件事是重新安装ca-certificates作为详细的here

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

另外要尝试的是明确允许有问题的一个站点的证书,如here所述(特别是如果一个站点是您自己的服务器并且您已经达到了.pem)。

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

升级到CentOS 6上的PHP 5.6后,我遇到了这个确切的错误,试图访问服务器本身,该服务器本身有一个cheapsslsecurity证书,可能需要更新,但我安装了一个letsencrypt证书,并且上面的这两个步骤确实诀窍。我不知道为什么第二步是必要的。


有用的命令

查看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

136
投票

你不应该只关闭验证。相反,你应该下载一个证书包,也许curl包会做?

然后你只需要把它放在你的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包中。如果不是,则在获得站点的根证书并将其放入证书文件之前,这仍然无效。


32
投票

我通过确保在我的机器上安装了OpenSSL然后将其添加到我的php.ini来修复此问题:

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

14
投票

您可以通过编写使用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开头的网址,就可以使用file_get_contents_curl而不是file_get_contents


11
投票

如果您的PHP版本是5,请尝试通过在终端中键入以下命令来安装cURL:

sudo apt-get install php5-curl

7
投票

您基本上必须将环境变量SSL_CERT_FILE设置为从以下链接下载的ssl-certificate的PEM文件的路径:http://curl.haxx.se/ca/cacert.pem

我花了很多时间来解决这个问题。


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不具有此设置,因此它必须与常规证书位于同一文件中。


5
投票

为我工作,我使用的是PHP 5.6。 openssl扩展应该启用,并在调用google map api verify_peer make false下面的代码对我有用。

<?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; ?>
© www.soinside.com 2019 - 2024. All rights reserved.