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) 是来自主要受信任证书颁发机构的根证书 bundle 。你说远程主机有一个自签名的 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/32211301/

相关文章:

PHP mysql_fetch_object,所有属性都是字符串?

php - Laravel Mail::send() 发送到多个 to 或 bcc 地址

php - 无法使用 file_get_contents 找到包装器 "https"

php - 如何使环境变量可用于 Apache,作为服务启动?

linux - 这是公共(public)/ key 登录的良好设置吗?

c++ - 如何使用 Openssl 编码 ASN.1 上下文特定

javascript - Codeigniter Javascript 动态输入仅提交第一项

PHP-MYSQL语法错误

php - Laravel 5.6 部署的应用程序路由给出 404 错误

python-3.x - 无法获取本地颁发者证书 mac OS