Ошибка SSL сертификата при подключении к API Сбербанка через CURL
При попытке отправить запрос к API Сбербанка с помощью PHP-функции curl_exec() вы можете столкнуться с сообщением: Problem with the local SSL certificate. Это типичная проблема для разработчиков, которые вручную указывают путь к сертификату. В этой статье мы подробно разберём, почему возникает эта ошибка и как её исправить.
Почему возникает ошибка Problem with the local SSL certificate
Ошибка свидетельствует о том, что cURL не может проверить или загрузить локальный SSL-сертификат. Чаще всего это связано с неправильным форматом файла, неверным путём или отсутствием поддержки формата PKCS#12 (.p12) в вашей сборке PHP. Даже если файл физически доступен по URL, cURL ожидает локальный путь к файлу на сервере, а не URL.
В вашем коде указаны URL-адреса для CURLOPT_SSLCERT и CURLOPT_CAINFO, что является основной причиной сбоя. cURL не умеет загружать сертификаты по HTTP/HTTPS - он требует абсолютный путь на файловой системе хостинга.
Как правильно указать путь к сертификату
Для корректной работы замените URL на реальный путь к файлу на сервере. Например, если ваш скрипт находится в /admin/sber.php, а сертификат лежит в /admin/SSL/file.p12, используйте:
curl_setopt($ch, CURLOPT_SSLCERT, __DIR__ . '/SSL/certificate_fbb85415-7416-4a5d-aa54-93321dc2306d.p12');Константа __DIR__ возвращает директорию текущего скрипта. Аналогично поступите с CURLOPT_CAINFO:
curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . '/SSL/russian-trusted-cacert.pem');Дополнительные настройки для API Сбербанка
Помимо пути к сертификату, убедитесь, что вы используете правильные опции cURL для работы с PKCS#12. Добавьте следующие настройки:
- CURLOPT_SSLCERTTYPE - укажите
P12, чтобы явно сообщить cURL формат файла. - CURLOPT_SSLKEYPASSWD - пароль от сертификата (дублирует CURLOPT_SSLCERTPASSWD).
- CURLOPT_SSL_VERIFYPEER - установите в
trueдля продакшена, но для теста можно временно отключить.
Пример рабочего блока настроек:
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'P12');
curl_setopt($ch, CURLOPT_SSLCERT, __DIR__ . '/SSL/cert.p12');
curl_setopt($ch, CURLOPT_SSLCERTPASSWD, 'ваш_пароль');
curl_setopt($ch, CURLOPT_CAINFO, __DIR__ . '/SSL/cacert.pem');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);Что делать, если нет доступа к файловой системе
На виртуальном хостинге без SSH вы всё равно можете узнать абсолютный путь. Создайте временный PHP-файл с кодом:
<?php echo __DIR__; ?>Запустите его в браузере - вы увидите полный путь к директории. Затем скорректируйте пути в curl_setopt. Если файлы сертификатов лежат в той же папке, что и скрипт, путь будет, например: /home/user/public_html/admin/SSL/file.p12.
Проверка прав доступа и формата файла
Убедитесь, что файлы сертификатов читаемы. Права 777 избыточны, достаточно 644 (владелец - пользователь веб-сервера). Также проверьте, что сертификат в формате .p12 не повреждён - попробуйте открыть его на локальном компьютере с помощью OpenSSL:
openssl pkcs12 -info -in certificate.p12Если команда выполняется без ошибок, сертификат корректен.
Ошибка после исправления путей
Если после замены URL на локальные пути ошибка сохраняется, проверьте версию PHP и сборку cURL. На некоторых хостингах поддержка PKCS#12 отключена. В этом случае конвертируйте сертификат в формат PEM (сертификат + ключ) и используйте опции CURLOPT_SSLCERT и CURLOPT_SSLKEY отдельно.
Для конвертации выполните на локальной машине:
openssl pkcs12 -in certificate.p12 -out cert.pem -nokeys
openssl pkcs12 -in certificate.p12 -out key.pem -nocerts -nodesЗатем загрузите оба файла на хостинг и укажите:
curl_setopt($ch, CURLOPT_SSLCERT, 'путь_к_cert.pem');
curl_setopt($ch, CURLOPT_SSLKEY, 'путь_к_key.pem');
curl_setopt($ch, CURLOPT_CAINFO, 'путь_к_cacert.pem');