Подтвердить что ты не робот

Ошибка 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"

Но script все еще не работает

Обновление

Это работает

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 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: проверка сертификата не выполнена

4b9b3361

Ответ 1

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

Вам нужно будет найти сертификат ЦС, который был сгенерирован на сервере, который подписал сертификат 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 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

Проблема заключается в новой версии PHP в macOS Sierra

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

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

Ответ 3

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

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

Ответ 4

Добавить

$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";

Ответ 5

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

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

Здесь перечислены параметры контекста SSL в PHP: https://secure.php.net/manual/en/context.ssl.php

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

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

Ответ 6

В моем случае я был на 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 для получения дополнительной информации о том, что делать и как это сделать.:)

Ответ 7

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

Ответ 8

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

Ответ 9

Пробовали ли вы использовать метод stream_context_set_option()?

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

Кроме того, попробуйте file_get_contents() для файла pem, чтобы убедиться, что у вас есть разрешения на его доступ, и убедитесь, что имя хоста соответствует сертификату.