php - SSL 错误 SSL3_GET_SERVER_CERTIFICATE :certificate verify failed

标签 php apache openssl

升级到 PHP 5.6 后,尝试通过 fsockopen() 连接到服务器时出现错误..

服务器(主机)上的证书是自签名的

PHP Warning: fsockopen(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

代码

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 Warning: stream_socket_client(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed

最佳答案

您下载的文件 (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 证书的 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);

}

关于php - SSL 错误 SSL3_GET_SERVER_CERTIFICATE :certificate verify failed,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38113860/

相关文章:

openssl - openssl.cnf 文件的正确位置

php - 执行次数与数据库中的数据一样多,但最多。 5次

php - 如何避免对我的数据库的大量调用? (MySQL + PHP)

javascript - 获取存储在多个 HTML 元素中的数据

java - OS X 上的 Openssl key 生成失败

c++ - ECDSA key 对生成输出错误

基于 PHP 的可打印版本

Apache 别名虚拟主机

python - 使用 python 设置 apache 服务器范围的变量

apache - 当 SSL 证书为非 www 时,在 https www 上将 www 重写为非 www 失败