ChatGPT解决这个技术问题 Extra ChatGPT

SSL 错误 SSL3_GET_SERVER_CERTIFICATE:证书验证失败

After upgrading to PHP 5.6 I get an error when trying to connect to a server via 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

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

$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

Already have tried that.. I can't locate the file
You have to look at the details. There are a variety of possible causes but not using the same domain as appears in the certificate is a common one. Can you access it without an error using curl -v? Also note that unless those versions of openssl have had all the security patches backported you may want to upgrade.
The issue is not the server.. It works. Its the client-side which causes the problem
Which OS are you using?

m
miken32

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)

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. 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.

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.

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

}

It should work with fsockopen alone.. This is much too complicated
I'm not sure what distribution of linux you're using, but try running sudo service apache2 restart. It may be that you need to restart apache after adding the openssl.cafile line to php.ini
@clarkk The host you're connecting to, is the SSL certificate for that host a self-signed certificate that you have the CA certificate for? PHP 5.6 now validates SSL certificates when using fsockopen, so the CA certificate used to sign the remote host's SSL certificate needs to be trusted on your system. My answer above is just another way to use a specific certificate for the request.
I always restart apache after config change.. But the cert on the server (host) is self-signed
@clarkk Could you try the code that I posted to see if it does actually work? Because if it does then we can address trusting the CA certificate on your host so fsockopen will work. If it doesn't work at all, then there's something else wrong.
V
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.

Because of minimalist Docker-oriented base image I had missing ca-certificates package and simple apt-get install ca-certificates helped me.


Finally, after searching for so long, this helped ! Thank you !
H
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";

N
Nguyễn Quang Tuấn

The problem is in new PHP Version in macOS Sierra

Please add

stream_context_set_option($ctx, 'ssl', 'verify_peer', false);

It worked for me in Production environment, but in sandbox it is working. Can you please put some light on it?
Note that this is not secure as it tells PHP to ignore the fact that the peer is not a valid match.
@AlexisWilke : thank you, i know that, but i cant find other solutions for this issue. if you have any good idea, please tell me
First of all, I think your answer you say that there is a security risk involved in turning off the peer verification, hence my comment. As for a solution, it could be that the server still uses SSL3 which has been deprecated. So you should not access that server anymore until it gets upgraded...
add where exactly sir ??
n
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...

# 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. :)


I
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


D
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?

Here's a list of SSL context options in PHP: 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.

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.


The first solution of "do you trust yourself?" is the correct one: add yourself to the trust store. The second one is actively harmful: "do you trust yourself? Yeah, now you can trust anyone who says they're you!"
C
Community

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


u
uri2x

Have you tried using the stream_context_set_option() method ?

$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.


echo file_get_contents("/etc/ssl/certs/cacert.pem"); <-- this works
fsockopen only supports five arguments. php.net/manual/en/function.fsockopen.php

关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅