it-swarm.com.ru

Ошибка SSL SSL3_GET_SERVER_CERTIFICATE: сбой проверки сертификата

После обновления до 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: сбой проверки сертификата

39
clarkk

Файл, который вы загрузили ( http://curl.haxx.se/ca/cacert.pem ), представляет собой набор корневых сертификатов основных доверенных центров сертификации. Вы сказали, что удаленный хост имеет самозаверяющий сертификат SSL, поэтому он не использует доверенный сертификат. Параметр openssl.cafile должен указывать на сертификат CA, который использовался для подписи сертификата SSL на удаленном хосте. PHP 5.6 был улучшен по сравнению с предыдущими версиями PHP, чтобы теперь проверять сертификаты одноранговых узлов и имена хостов по умолчанию ( http://php.net/manual/en/migration56.openssl.php )

Вам нужно найти сертификат CA, сгенерированный на сервере, который подписал сертификат SSL, и скопировать его на этот сервер. Единственный другой вариант - отключить проверку однорангового узла, но это нарушает безопасность SSL. Если вы хотите отключить проверку, попробуйте этот массив с кодом из моего предыдущего ответа:

$contextOptions = array(
    'ssl' => array(
        'verify_peer' => false,
        'verify_peer_name' => false
    )
);

В любом случае, если вы используете самозаверяющие сертификаты, вам нужно добавить сертификат CA, который использовался для подписи SSL-сертификата удаленного хоста, в доверенное хранилище на сервере, который вы подключаете с помощью OR. потоковые контексты для использования этого сертификата для каждого отдельного запроса. Добавление его в доверенные сертификаты является самым простым решением. Просто добавьте содержимое сертификата 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);

}
29
aecend

Проблема в новой PHP версии в macOS Sierra

Пожалуйста, добавьте 

stream_context_set_option($ctx, 'ssl', 'verify_peer', false);
7
Nguyễn Quang Tuấn

С аналогичной проблемой я столкнулся при работе с Ubuntu 16.04 при использовании Docker. В моем случае это была проблема с Composer, но сообщение об ошибке (и, следовательно, проблема) было то же самое.

Из-за минималистичного Docker-ориентированного базового образа у меня отсутствовал пакет ca-certificates, и простой apt-get install ca-certificates помог мне.

4
Vladimir Posvistelik

Добавлять 

$mail->SMTPOptions = array(
'ssl' => array(
    'verify_peer' => false,
    'verify_peer_name' => false,
    'allow_self_signed' => true
));

до

mail->send()

и заменить

require "mailer/class.phpmailer.php";

с

require "mailer/PHPMailerAutoload.php";
3
Himanshu Sharma

Вы упоминаете, что сертификат является самоподписанным (вами)? Тогда у вас есть два варианта:

  • добавьте сертификат в ваше хранилище доверенных сертификатов (получение cacert.pem с веб-сайта cURL ничего не даст, поскольку он самоподписан)
  • не надо проверять сертификат: ты доверяешь себе, не так ли?

Вот список параметров контекста SSL в PHP: https://secure.php.net/manual/en/context.ssl.php

Установите allow_self_signed, если вы импортируете свой сертификат в доверенное хранилище, или установите verify_peer в false, чтобы пропустить проверку.

Причина, по которой мы доверяем конкретному сертификату, заключается в том, что мы доверяем его эмитенту. Поскольку ваш сертификат самоподписан, ни один клиент не будет доверять сертификату, поскольку подписавшая сторона (вы) не является доверенной. Если вы создали свой собственный CA при подписании сертификата, вы можете добавить CA в ваше хранилище доверенных сертификатов. Если ваш сертификат не содержит ЦС, вы не можете ожидать, что кто-то подключится к вашему серверу.

0
DavidS

В моем случае я работал на CentOS 7, и моя установка php указывала на сертификат, генерируемый с помощью update-ca-trust. Символическая ссылка была /etc/pki/tls/cert.pem, указывающая на /etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem. Это был просто тестовый сервер, и я хотел, чтобы мой самоподписанный сертификат работал правильно. Так что в моем случае ...

# 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

Тогда некоторые из моих вызовов API начали работать, поскольку моему сертификату теперь доверяли. Также, если ваше ca-trust будет обновлено через yum или что-то еще, это восстановит ваши корневые сертификаты и все равно включит ваш самоподписанный сертификат. Запустите man update-ca-trust для получения дополнительной информации о том, что делать и как это сделать. :)

0
n0nag0n

Если вы используете macOS sierra, в версии PHP есть обновление. вам необходимо добавить файл центра сертификации Entrust.net (2048) в код PHP. дополнительная информация проверить принятый ответ здесь Push-уведомление в PHP с использованием файла PEM

0
Im Batman

Прежде всего, убедитесь, что антивирусное программное обеспечение не блокирует SSL2.
Потому что долго не мог решить проблему и мне помогло только отключение антивируса

0
Igor Shumichenko