升级到PHP 5.6后,尝试通过fsockopen()
连接到服务器时出错。
服务器(主机)上的证书是自签名的
PHP警告:fsockopen():SSL操作失败,代码为1. OpenSSL错误消息: 错误:14090086:SSL例程:SSL3_GET_SERVER_CERTIFICATE:证书验证失败
if($fp = fsockopen($host, $port, $errno, $errstr, 20)){
$this->request = 'POST '.substr($this->url, strlen($this->host)).' HTTP/1.1'.$crlf
.'Host: '.$this->host.$crlf
.'Content-Length: '.$content_length.$crlf
.'Connection: Close'.$crlf.$crlf
.$body;
fwrite($fp, $this->request);
while($line = fgets($fp)){
if($line !== false){
$this->response .= $line;
}
}
fclose($fp);
}
# cd /etc/ssl/certs/
# wget http://curl.haxx.se/ca/cacert.pem
的php.ini
openssl.cafile = "/etc/ssl/certs/cacert.pem"
但是剧本仍无法正常工作
这有效
echo file_get_contents("/etc/ssl/certs/cacert.pem");
$contextOptions = array(
'ssl' => array(
'verify_peer' => true, // You could skip all of the trouble by changing this to false, but it's WAY uncool for security reasons.
'cafile' => '/etc/ssl/certs/cacert.pem',
//'CN_match' => 'example.com', // Change this to your certificates Common Name (or just comment this line out if not needed)
'ciphers' => 'HIGH:!SSLv2:!SSLv3',
'disable_compression' => true,
)
);
$context = stream_context_create($contextOptions);
$fp = stream_socket_client("{$host}:{$port}", $errno, $errstr, 20, STREAM_CLIENT_CONNECT, $context);
错误
PHP警告:stream_socket_client():SSL操作失败,代码为1. OpenSSL错误消息: 错误:14090086:SSL例程:SSL3_GET_SERVER_CERTIFICATE:证书验证失败
答案 0 :(得分:31)
您下载的文件(http://curl.haxx.se/ca/cacert.pem)是来自主要受信任证书颁发机构的一组根证书。您说远程主机具有自签名SSL证书,因此它不使用可信证书。 openssl.cafile
设置需要指向用于在远程主机上签署SSL证书的CA证书。 PHP 5.6已经比以前版本的PHP改进,现在默认验证对等证书和主机名(http://php.net/manual/en/migration56.openssl.php)
您需要找到在签署SSL证书的服务器上生成的CA证书,并将其复制到此服务器。唯一的另一种选择是禁用验证对等体,但这会破坏SSL安全性。如果您想尝试禁用验证,请使用我之前回答中的代码尝试此数组:
$contextOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false
)
);
无论哪种方式,如果您使用的是自签名证书,则需要将用于签署远程主机SSL证书的CA证书添加到您要连接的服务器上的受信任存储中,或者使用流上下文为每个请求使用该证书。将其添加到可信证书是最简单的解决方案。只需将远程主机CA证书的内容添加到您下载的cacert.pem文件的末尾即可。
<强>上:强>
fsockopen不支持流上下文,因此请改用stream_socket_client。它返回一个资源,可以与fsockopen资源可以使用的所有命令一起使用。
这应该是您在问题中的代码段的替代品:
<?php
$contextOptions = array(
'ssl' => array(
'verify_peer' => true, // You could skip all of the trouble by changing this to false, but it's WAY uncool for security reasons.
'cafile' => '/etc/ssl/certs/cacert.pem',
'CN_match' => 'example.com', // Change this to your certificates Common Name (or just comment this line out if not needed)
'ciphers' => 'HIGH:!SSLv2:!SSLv3',
'disable_compression' => true,
)
);
$context = stream_context_create($contextOptions);
$fp = stream_socket_client("tcp://{$host}:{$port}", $errno, $errstr, 20, STREAM_CLIENT_CONNECT, $context);
if (!$fp) {
echo "$errstr ({$errno})<br />\n";
}else{
$this->request = 'POST '.substr($this->url, strlen($this->host)).' HTTP/1.1'.$crlf
.'Host: '.$this->host.$crlf
.'Content-Length: '.$content_length.$crlf
.'Connection: Close'.$crlf.$crlf
.$body;
fwrite($fp, $this->request);
while (!feof($fp)) {
$this->response .= fgets($fp);
}
fclose($fp);
}
答案 1 :(得分:7)
问题在于macOS Sierra中的新PHP版本
请添加
stream_context_set_option($ctx, 'ssl', 'verify_peer', false);
答案 2 :(得分:4)
使用Docker在使用Ubuntu 16.04时遇到了类似的问题。在我的情况下,这是Composer的问题,但错误信息(因此问题)是相同的。
由于极简主义的面向Docker的基本图像,我丢失了ca-certificates
包,简单的apt-get install ca-certificates
帮助了我。
答案 3 :(得分:3)
添加
$mail->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
));
前
mail->send()
并替换
require "mailer/class.phpmailer.php";
与
require "mailer/PHPMailerAutoload.php";
答案 4 :(得分:1)
首先,请确保防病毒软件不会阻止SSL2。
因为我很长一段时间都无法解决问题,仅禁用防病毒软件对我有帮助
答案 5 :(得分:0)
您提到证书是自签名的(由您)?那你有两个选择:
cacert.pem
无法执行任何操作,因为它已自签名)这是PHP中的SSL上下文选项列表: https://secure.php.net/manual/en/context.ssl.php
如果您将证书导入信任库,请设置allow_self_signed
,或将verify_peer
设置为false以跳过验证。
我们信任特定证书的原因是因为我们信任其颁发者。由于您的证书是自签名的,因此签名者(您)不受信任,因此任何客户都不会信任该证书。如果在签署证书时创建了自己的CA,则可以将CA添加到信任库。如果您的证书不包含任何CA,那么您就不能指望任何人连接到您的服务器。
答案 6 :(得分:0)
在我的情况下,我在CentOS 7上,我的php安装指向通过update-ca-trust
生成的证书。符号链接/etc/pki/tls/cert.pem
指向/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
。这只是一个测试服务器,我希望我的自签名证书能够正常工作。所以在我的情况下...
# My root ca-trust folder was here. I coped the .crt file to this location
# and renamed it to a .pem
/etc/pki/ca-trust/source/anchors/self-signed-cert.pem
# Then run this command and it will regenerate the certs for you and
# include your self signed cert file.
update-ca-trust
然后我的一些api调用开始工作,因为我的证书现在被信任了。此外,如果您的ca-trust通过yum或其他内容进行更新,这将重建您的根证书并仍然包含您的自签名证书。运行man update-ca-trust
以获取有关如何操作以及如何操作的详细信息。 :)
答案 7 :(得分:0)
如果您使用的是macOS sierra,则会有PHP版本的更新。您需要将Entrust.net证书颁发机构(2048)文件添加到PHP代码中。更多信息,请在此处Push Notification in PHP using PEM file
查看已接受的答案