php SSL 错误 SSL3_GET_SERVER_CERTIFICATE:证书验证失败
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32211301/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
SSL error SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
提问by clarkk
After upgrading to PHP 5.6 I get an error when trying to connect to a server via fsockopen()
..
升级到 PHP 5.6 后,尝试通过fsockopen()
..连接到服务器时出现错误。
The certificate on the server (host) is self-signed
服务器(主机)上的证书是自签名的
PHP Warning: fsockopen(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
PHP 警告:fsockopen():SSL 操作失败,代码为 1。OpenSSL 错误消息:错误:14090086:SSL 例程:SSL3_GET_SERVER_CERTIFICATE:证书验证失败
code
代码
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);
}
Have tried
试过
# cd /etc/ssl/certs/
# wget http://curl.haxx.se/ca/cacert.pem
php.ini
配置文件
openssl.cafile = "/etc/ssl/certs/cacert.pem"
But the script still fails to work
但是脚本仍然无法工作
update
更新
This works
这有效
echo file_get_contents("/etc/ssl/certs/cacert.pem");
update 2
更新 2
$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);
error
错误
PHP Warning: stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
PHP 警告:stream_socket_client():SSL 操作失败,代码为 1。OpenSSL 错误消息:错误:14090086:SSL 例程:SSL3_GET_SERVER_CERTIFICATE:证书验证失败
采纳答案by aecend
The file that you downloaded (http://curl.haxx.se/ca/cacert.pem) is a bundle of the root certificates from the major trusted certificate authorities. You said that the remote host has a self-signed SSL certificate, so it didn't use a trusted certificate. The openssl.cafile
setting needs to point to the CA certificate that was used to sign the SSL certificate on the remote host. PHP 5.6 has been improved over previous versions of PHP to now verify peer certificates and host names by default (http://php.net/manual/en/migration56.openssl.php)
您下载的文件 ( http://curl.haxx.se/ca/cacert.pem) 是来自主要受信任证书颁发机构的一组根证书。你说远程主机有一个自签名的 SSL 证书,所以它没有使用受信任的证书。该openssl.cafile
设置需要指向用于签署远程主机上的 SSL 证书的 CA 证书。PHP 5.6 比以前的 PHP 版本有所改进,现在默认验证对等证书和主机名 ( http://php.net/manual/en/migration56.openssl.php)
You'll need to locate the CA certificate that was generated on the server that signed the SSL certificate and copy it to this server. The only other option is to disable verifying the peer, but that defeats the SSL security. If you DO want to try disabling verification, try this array with the code from my previous answer:
您需要找到在签署 SSL 证书的服务器上生成的 CA 证书并将其复制到此服务器。唯一的其他选择是禁用对等方的验证,但这会破坏 SSL 安全性。如果您确实想尝试禁用验证,请使用我之前的答案中的代码尝试此数组:
$contextOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false
)
);
Either way, if you're using self-signed certificates, you'll need to add the CA cert that was used to sign the remote host's SSL certificate to the trusted store on the server you're connecting from OR use stream contexts to use that certificate for each individual request. Adding it to the trusted certificates is the simplest solution. Just add the contents of the remote host's CA cert to the end of the cacert.pem file you downloaded.
无论哪种方式,如果您使用自签名证书,则需要将用于签署远程主机的 SSL 证书的 CA 证书添加到您正在连接的服务器上的受信任存储中,或者使用流上下文来使用每个单独请求的证书。将其添加到受信任证书是最简单的解决方案。只需将远程主机的 CA 证书的内容添加到您下载的 cacert.pem 文件的末尾即可。
Previous:
以前的:
fsockopen doesn't support stream contexts, so use stream_socket_client instead. It returns a resource that can be used with all the commands that fsockopen resources can.
fsockopen 不支持流上下文,因此请改用 stream_socket_client。它返回一个可以与 fsockopen 资源可以使用的所有命令一起使用的资源。
This should be a drop in replacement for the snippet you have in your question:
这应该是您问题中的片段的替代品:
<?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);
}
回答by Nguy?n Quang Tu?n
The problem is in new PHP Version in macOS Sierra
问题出在 macOS Sierra 的新 PHP 版本中
Please add
请加
stream_context_set_option($ctx, 'ssl', 'verify_peer', false);
回答by Vladimir Posvistelik
I faced a similar issue during work with Ubuntu 16.04 by using Docker. In my case that was a problem with Composer, but error message (and thus the problem) was the same.
在使用 Docker 使用 Ubuntu 16.04 期间,我遇到了类似的问题。就我而言,这是 Composer 的问题,但错误消息(以及问题)是相同的。
Because of minimalist Docker-oriented base image I had missing ca-certificates
package and simple apt-get install ca-certificates
helped me.
由于面向 Docker 的极简主义基础映像,我缺少ca-certificates
包,并且 simpleapt-get install ca-certificates
帮助了我。
回答by Himanshu Sharma
Add
添加
$mail->SMTPOptions = array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
'allow_self_signed' => true
));
before
前
mail->send()
and replace
并替换
require "mailer/class.phpmailer.php";
with
和
require "mailer/PHPMailerAutoload.php";
回答by Igor Shumichenko
Firstable, make sure that you Antivirus software doesn't block SSL2.
Because I could not solve a problem for a long time and only disabling the antivirus helped me
首先,请确保您的防病毒软件不会阻止 SSL2。
因为我长时间无法解决问题,只有禁用防病毒软件对我有所帮助
回答by Im Batman
If you are using macOS sierra there is a update in PHP version. you need to have Entrust.net Certificate Authority (2048) file added to the PHP code. more info check accepted answer here Push Notification in PHP using PEM file
如果您使用的是 macOS sierra,则 PHP 版本会有更新。您需要将 Entrust.net 证书颁发机构 (2048) 文件添加到 PHP 代码中。更多信息检查接受的答案在这里使用 PEM 文件在 PHP 中推送通知
回答by DavidS
You mention the certificate is self-signed (by you)? Then you have two choices:
你提到证书是自签名的(由你)?那么你有两个选择:
- add the certificate to your trust store (fetching
cacert.pem
from cURL website won't do anything, since it's self-signed) - don't bother verifying the certificate: you trust yourself, don't you?
- 将证书添加到您的信任存储(
cacert.pem
从 cURL 网站获取不会做任何事情,因为它是自签名的) - 不要费心验证证书:你相信自己,不是吗?
Here's a list of SSL context options in PHP: https://secure.php.net/manual/en/context.ssl.php
这是 PHP 中的 SSL 上下文选项列表:https: //secure.php.net/manual/en/context.ssl.php
Set allow_self_signed
if you import your certificate into your trust store, or set verify_peer
to false to skip verification.
设置allow_self_signed
是否将证书导入信任库,或设置verify_peer
为 false 以跳过验证。
The reason why we trust a specific certificate is because we trust its issuer. Since your certificate is self-signed, no client will trust the certificate as the signer (you) is not trusted. If you created your own CA when signing the certificate, you can add the CA to your trust store. If your certificate doesn't contain any CA, then you can't expect anyone to connect to your server.
我们之所以信任特定证书,是因为我们信任它的颁发者。由于您的证书是自签名的,因此没有客户端会信任该证书,因为签名者(您)不受信任。如果您在签署证书时创建了自己的 CA,则可以将该 CA 添加到您的信任存储中。如果您的证书不包含任何 CA,那么您不能指望任何人连接到您的服务器。
回答by n0nag0n
In my case, I was on CentOS 7 and my php installation was pointing to a certificate that was being generated through update-ca-trust
. The symlink was /etc/pki/tls/cert.pem
pointing to /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem
. This was just a test server and I wanted my self signed cert to work properly. So in my case...
就我而言,我在 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
Then some of my api calls started working as my cert was now trusted. Also if your ca-trust gets updated through yum or something, this will rebuild your root certificates and still include your self signed cert. Run man update-ca-trust
for more info on what to do and how to do it. :)
然后我的一些 api 调用开始工作,因为我的证书现在受到信任。此外,如果您的 ca-trust 通过 yum 或其他方式更新,这将重建您的根证书并仍然包含您的自签名证书。运行man update-ca-trust
以获取有关该做什么以及如何做的更多信息。:)
回答by uri2x
Have you tried using the stream_context_set_option()
method ?
您是否尝试过使用该stream_context_set_option()
方法?
$context = stream_context_create();
$result = stream_context_set_option($context, 'ssl', 'local_cert', '/etc/ssl/certs/cacert.pem');
$fp = fsockopen($host, $port, $errno, $errstr, 20, $context);
In addition, try file_get_contents()
for the pem file, to make sure you have permissions to access it, and make sure the host name matches the certificate.
此外,尝试file_get_contents()
获取 pem 文件,以确保您有权访问它,并确保主机名与证书匹配。