Ошибка 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');

    Часто задаваемые вопросы