SSL 错误SSL3_GET_SERVER_CERTIFICATE:证书验证失败法典试过更新更新 2

2022-08-30 09:53:45

升级到 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");

更新 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);

错误

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


答案 1

您下载的文件(http://curl.haxx.se/ca/cacert.pem)是来自主要受信任证书颁发机构的根证书的捆绑包。您说远程主机具有自签名 SSL 证书,因此它没有使用受信任的证书。该设置需要指向用于在远程主机上对 SSL 证书进行签名的 CA 证书。PHP 5.6 比以前版本的 PHP 进行了改进,现在可以默认验证对等证书和主机名(http://php.net/manual/en/migration56.openssl.phpopenssl.cafile)

您需要找到在签署 SSL 证书的服务器上生成的 CA 证书,并将其复制到此服务器。如果使用自签名证书,则需要将用于对远程主机的 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);

}

答案 2

在使用 Docker 使用 Ubuntu 16.04 时,我遇到了类似的问题。在我的情况下,这是Composer的问题,但错误消息(以及问题)是相同的。

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


推荐