PHP cURL и SSL: варианты настройки безопасности
Библиотека 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).
Расширенные примеры использования 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 ресурсов.