PHP cURL и SSL: варианты настройки безопасности

Раздел: PHP -> HTTP запросы с cURL

Библиотека cURL в PHP предоставляет мощный инструмент для выполнения HTTP запросов. При работе с HTTPS необходимо корректно настроить параметры SSL, чтобы обеспечить безопасное соединение. В этой статье рассмотрены различные способы конфигурации SSL в cURL: от базовой верификации до обработки нестандартных сертификатов.

Методы настройки SSL в cURL

Основной подход: верификация сертификата с использованием CA bundle

Наиболее безопасный способ - включить проверку подлинности сертификата сервера. Для этого curl должен знать, каким удостоверяющим центрам доверять. В PHP можно указать путь к файлу CA bundle (например, cacert.pem, скачанному с curl.se).

<?
$ch = curl_init('https://example.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_CAINFO, '/path/to/cacert.pem');
$response = curl_exec($ch);
curl_close($ch);
?>

Php curl timeout (php curl таймаут)

Пояснение:

  • CURLOPT_SSL_VERIFYPEER - включает проверку сертификата (true).
  • CURLOPT_SSL_VERIFYHOST - проверяет, что имя хоста в сертификате совпадает с запрошенным (2 - строгая проверка).
  • CURLOPT_CAINFO - указывает путь к файлу с корневыми сертификатами.

Как отключить проверку SSL (для локальной разработки)?

В тестовой среде иногда требуется отключить верификацию. Это небезопасно для продакшена.

curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

Php curl ssl (php curl ssl)

Возможные проблемы:

  • Уязвимость к MITM атакам.
  • Некоторые версии cURL могут генерировать предупреждения в логах.

Как указать собственный CA файл, если нет доступа к глобальному хранилищу?

Можно загрузить bundle или использовать сертификат конкретного центра.

curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . '/cacert.pem');
// или CAPATH - директория с сертификатами, хэшированными по OpenSSL
curl_setopt($ch, CURLOPT_CAPATH, '/etc/ssl/certs');

Php curl ответ (ответ php curl)

Как использовать клиентский сертификат для взаимной аутентификации?

Когда сервер требует сертификат клиента, его можно передать через cURL.

curl_setopt($ch, CURLOPT_SSLCERT, '/path/to/client.crt');
curl_setopt($ch, CURLOPT_SSLCERTPASSWD, 'password');
curl_setopt($ch, CURLOPT_SSLKEY, '/path/to/client.key');
curl_setopt($ch, CURLOPT_SSLKEYPASSWD, 'keypass');

Php curl authorization (php curl авторизация)

Типичные ошибки:

  • Неверный формат сертификата (PEM/DER).
  • Ошибка пароля - если ключ защищён, а пароль не указан.

Как игнорировать проверку имени хоста (CURLOPT_SSL_VERIFYHOST)?

Отключение проверки имени хоста (уровень 0 или 1) может потребоваться для самоподписанных сертификатов.

curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); // 0 - полное отключение

Php curl close (php curl close)

Внимание:

При значении 1 или 0 соединение всё ещё может быть шифрованным, но безопасность снижается.

Как работать с самоподписанным сертификатом, добавляя его в доверенные?

Можно использовать CURLOPT_CAINFO, указав путь к самоподписанному сертификату (PEM).

curl_setopt($ch, CURLOPT_CAINFO, '/path/to/self-signed.pem');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

Часто встречающиеся ошибки SSL в cURL и способы их решения

  • SSL certificate problem: unable to get local issuer certificate - отсутствует или неверный CA bundle. Укажите CURLOPT_CAINFO с корректным файлом.
  • SSL: certificate subject name does not match target host - несовпадение имени хоста. Проверьте CURLOPT_SSL_VERIFYHOST или сертификат.
  • error:14090086:SSL routines:ssl3_get_server_certificate:certificate verify failed - общая ошибка верификации. Включите подробную отладку: CURLOPT_VERBOSE.
  • OpenSSL SSL_connect: SSL_ERROR_SYSCALL - проблемы с сетью или версией SSL. Попробуйте установить CURLOPT_SSLVERSION (например, CURL_SSLVERSION_TLSv1_2).
- Curl exec php (php curl exec)
- Curl setopt php (php curl setopt)
- Php curl file (php curl файл)

Расширенные примеры использования SSL в cURL

Ниже приведены более сложные сценарии, которые помогут глубже понять настройку SSL. Каждый пример сопровождается кодом и результатом (где это возможно).

Пример 1. Получение информации о сертификате сервера

После выполнения запроса можно извлечь данные сертификата с помощью curl_getinfo.

Пример
<?
$ch = curl_init('https://www.google.com');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_CAINFO, '/path/to/cacert.pem');
curl_exec($ch);

$certinfo = curl_getinfo($ch, CURLINFO_CERTINFO);
print_r($certinfo);
curl_close($ch);
?>
Array
(
    [0] => Array
        (
            [Subject] => CN=www.google.com
            [Issuer] => CN=GTS CA 1O1,O=Google Trust Services,C=US
            [Version] => 3
            ...
        )
)

Пояснение:

CURLINFO_CERTINFO доступен при включённой опции CURLOPT_CERTINFO. Результат содержит массив данных сертификата.

Пример 2. Использование потока контекста (stream context) как альтернатива cURL

В PHP можно отправлять HTTPS запросы через файловые функции с контекстом SSL.

Пример
<?
$options = [
    'ssl' => [
        'verify_peer' => true,
        'cafile' => '/path/to/cacert.pem',
        'verify_depth' => 5,
    ]
];
$context = stream_context_create($options);
$data = file_get_contents('https://example.com', false, $context);
echo $data;
?>

Этот способ удобен для простых GET запросов, но уступает cURL в гибкости (например, отсутствие поддержки методов, заголовков).

Пример 3. Обработка ошибок SSL с повторной попыткой

В случае временной недоступности сервера или сбоя SSL может потребоваться повторная попытка с понижением версии протокола.

Пример
<?
function fetchWithSSLFallback($url) {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CAINFO => '/path/to/cacert.pem',
        CURLOPT_SSL_VERIFYPEER => true,
        CURLOPT_SSL_VERIFYHOST => 2,
        CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2
    ]);
    $response = curl_exec($ch);
    if ($response === false) {
        $error = curl_error($ch);
        if (strpos($error, 'SSL') !== false) {
            curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_1);
            $response = curl_exec($ch);
        }
    }
    curl_close($ch);
    return $response;
}
?>

Этот подход позволяет обходить ошибки, связанные с устаревшими версиями TLS на стороне сервера.

Пример 4. Загрузка сертификата CA из строки (без файла)

В некоторых окружениях нет доступа к файловой системе, сертификат можно передать через константу.

Пример
<?
$caCert = "-----BEGIN CERTIFICATE-----\nMIIFazCCA1OgAwIBAgIU...\n-----END CERTIFICATE-----";
$tempFile = tempnam(sys_get_temp_dir(), 'ca');
file_put_contents($tempFile, $caCert);

$ch = curl_init('https://example.com');
curl_setopt($ch, CURLOPT_CAINFO, $tempFile);
curl_exec($ch);
curl_close($ch);
unlink($tempFile);
?>

Внимание:

Сертификат сохраняется во временный файл во избежание конфликтов с правами.

Пример 5. Использование CURLOPT_SSLKEY и CURLOPT_SSLCERTTYPE

Если ключ и сертификат хранятся в разных форматах (P12, DER), необходимо указать тип.

Пример
<?
$ch = curl_init('https://example.com');
curl_setopt($ch, CURLOPT_SSLCERT, 'client.crt');
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLKEY, 'client.key');
curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLCERTPASSWD, 'secret');
?>

Для PKCS#12 используйте CURLOPT_SSLCERTTYPE = 'P12'.

Пример 6. Множественные запросы с общим SSL контекстом (curl_multi)

При параллельной загрузке через curl_multi настройки SSL применяются к каждому дескриптору отдельно.

Пример
<?
$mh = curl_multi_init();
$handles = [];
foreach (['https://site1.com', 'https://site2.com'] as $url) {
    $ch = curl_init($url);
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CAINFO => '/path/to/cacert.pem',
        CURLOPT_SSL_VERIFYPEER => true
    ]);
    curl_multi_add_handle($mh, $ch);
    $handles[] = $ch;
}
$running = null;
do {
    curl_multi_exec($mh, $running);
} while ($running);
foreach ($handles as $ch) {
    $response = curl_multi_getcontent($ch);
    echo $response;
    curl_multi_remove_handle($mh, $ch);
    curl_close($ch);
}
curl_multi_close($mh);
?>

Такой подход ускоряет загрузку нескольких HTTPS ресурсов.

PHP cURL SSL - comments

En
Php curl ssl (php)