SSL错误SSL3_GET_SERVER_CERTIFICATE:证书验证失败

cla*_*rkk 43 php apache openssl

升级到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);
}
Run Code Online (Sandbox Code Playgroud)

试过

# cd /etc/ssl/certs/
# wget http://curl.haxx.se/ca/cacert.pem
Run Code Online (Sandbox Code Playgroud)

php.ini中

openssl.cafile = "/etc/ssl/certs/cacert.pem"
Run Code Online (Sandbox Code Playgroud)

但脚本仍无法正常工作

更新

这有效

echo file_get_contents("/etc/ssl/certs/cacert.pem");
Run Code Online (Sandbox Code Playgroud)

更新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);
Run Code Online (Sandbox Code Playgroud)

错误

PHP警告:stream_socket_client():SSL操作失败,代码为1. OpenSSL错误消息:错误:14090086:SSL例程:SSL3_GET_SERVER_CERTIFICATE:证书验证失败

aec*_*end 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
    )
);
Run Code Online (Sandbox Code Playgroud)

无论哪种方式,如果您使用的是自签名证书,则需要将用于签署远程主机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);

}
Run Code Online (Sandbox Code Playgroud)


Ngu*_*uấn 6

问题出在macOS Sierra的新PHP版本中

请加

stream_context_set_option($ctx, 'ssl', 'verify_peer', false);
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这不安全,因为它告诉PHP忽略对等方不是有效匹配的事实. (3认同)
  • @AlexisWilke:谢谢,我知道这一点,但是我无法找到此问题的其他解决方案。如果您有什么好主意,请告诉我 (2认同)

Vla*_*lik 5

在使用Docker使用Ubuntu 16.04的过程中,我遇到了类似的问题。在我的情况下,这是Composer的问题,但是错误消息(因此也是问题)是相同的。

由于极简的面向Docker的基础映像,我缺少了ca-certificates软件包,并且简单地apt-get install ca-certificates帮助了我。