Подключение к внешним HTTP-сервисам с использованием клиентских SSL-сертификатов для авторизации может стать непростой задачей для разработчиков на платформе 1С:Предприятие. Нам предстоит рассмотреть типичные проблемы, с которыми сталкиваются пользователи при работе со встроенными средствами 1С, проводя тестирование http сервисов, и предложить рабочее решение, а также альтернативные подходы.
Платформа 1С:Предприятие предоставляет объект ЗащищенноеСоединениеOpenSSL для установки защищенных соединений. Для авторизации по клиентскому сертификату требуется предоставить файл клиентского сертификата в формате PKCS#12 (обычно с расширением .p12 или .pfx) и пароль к нему. Эти форматы содержат как публичную часть сертификата, так и закрытый ключ, необходимый для аутентификации.
Наш первоначальный подход, часто используемый разработчиками, выглядит следующим образом:
// Шаг 1: Конвертация .cer в .p12 (если исходный сертификат только публичный)
// Этот шаг выполняется вне 1С, например, с помощью утилиты OpenSSL.
// Пример команды OpenSSL для создания p12 из закрытого ключа (.key), сертификата (.crt) и цепочки УЦ (если есть):
// openssl pkcs12 -export -out cert.p12 -inkey private.key -in cert.crt -certfile CAcert.crt -name "MyClientCert" -passout pass:мойпароль
// Шаг 2: Создание защищенного соединения в 1С
// "e:\Install\pki.p12" - путь к файлу клиентского сертификата в формате PKCS#12
// "пароль" - пароль к файлу .p12
ССЛ = Новый ЗащищенноеСоединениеOpenSSL(Новый СертификатКлиентаФайл("e:\Install\pki.p12","пароль"));
// Хост HTTP-сервиса
Хост = "fglrr-site.its";
// Создание HTTP-соединения с использованием защищенного соединения
HTTPСоединение = Новый HTTPСоединение(Хост, , , , , ,ССЛ,);
// Пример HTTP-запроса
HTTPЗапрос = Новый HTTPЗапрос("/XAdES-TesT/Sign?WSDL");
// Формирование тела SOAP-запроса
СтрокаXML = "
|<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">
| <s:Body xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.001/XMLSchema"">
| <requestSignXAdES xmlns=""http://sign.server.procertum.unizeto/"">
| <certificate xmlns="">%СертБасе64%</certificate>
| <contentType xmlns="">application/octet-stream</contentType>
| <data xmlns="">%данные%</data>
| <signatureType xmlns="">ENVELOPING</signatureType>
| <validationDataFormat xmlns="">XADES</validationDataFormat>
| </requestSignXAdES>
| </s:Body>
|</s:Envelope>";
// Пример получения сертификата в Base64 для включения в тело SOAP
// Это действие НЕ связано с SSL-аутентификацией на уровне транспортного протокола.
// Оно требуется, если сам сервис ожидает сертификат в теле запроса для своих нужд.
СертДвоичнДанные = Новый ДвоичныеДанные("e:\Install\testq.cer");
СертБасе64 = ПолучитьСертификатBase64Строку(СертДвоичнДанные);
Функция ПолучитьСертификатBase64Строку(ДвоичнДанные) Экспорт
СтрокаBase64 = Base64Строка(ДвоичнДанные);
Значение = СтрЗаменить(СтрокаBase64, Символы.ВК, "");
Значение = СтрЗаменить(Значение, Символы.ПС, "");
Возврат Значение;
КонецФункции
СтрокаXML = СтрЗаменить(СтрокаXML,"%СертБасе64%",СертБасе64);
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаXML);
// Отправка запроса
Результат = HTTPСоединение.ОтправитьДляОбработки(HTTPЗапрос);
Ответ = Результат.ПолучитьТелоКакСтроку();
Сообщить(Ответ);
В данном случае, мы сталкиваемся с ошибкой "400 The SSL certificate error". Эта ошибка, как правило, указывает на то, что серверу не понравился клиентский сертификат, который был отправлен (или не отправлен) на этапе SSL-рукопожатия. Важно понимать, что встраивание сертификата в Base64 в тело SOAP-запроса (как показано выше) – это требование самого SOAP-сервиса на прикладном уровне, а не механизм SSL-аутентификации, который происходит на транспортном уровне, до того, как тело запроса будет обработано сервером.
Помимо клиентского сертификата, при установке защищенного соединения необходимо обеспечить проверку подлинности сертификата самого HTTP-сервера, к которому мы подключаемся. Для этого в конструкторе ЗащищенноеСоединениеOpenSSL можно использовать второй параметр – объект СертификатыУдостоверяющихЦентровФайл, который указывает на файл cacert.pem. Этот файл должен содержать корневые и промежуточные сертификаты удостоверяющих центров (УЦ), которым доверяет наша клиентская сторона 1С для проверки подлинности серверного сертификата.
Пример использования:
// "e:/!work/pki.p12.pem" - файл, содержащий корневые и промежуточные сертификаты УЦ,
// которым вы доверяете для проверки серверного сертификата.
// Важно: это НЕ тот же сертификат, что и клиентский .p12.
// Он должен включать сертификаты УЦ, выпустивших СЕРВЕРНЫЙ сертификат.
ССЛ = Новый ЗащищенноеСоединениеOpenSSL(Новый СертификатКлиентаФайл("e:/!work/pki.p12", "123"), Новый СертификатыУдостоверяющихЦентровФайл("e:/!work/pki.p12.pem"));
Если файл cacert.pem отсутствует, некорректен или не содержит нужных сертификатов УЦ, мы получим ошибку "Ошибка работы с Интернет: Удаленный узел не прошел проверку". Это означает, что 1С не смогла подтвердить подлинность сертификата сервера. Если мы получили именно эту ошибку, нам необходимо выполнить следующие шаги:
cacert.pem. Это обычно делается путем конкатенации содержимого файлов .cer (в формате Base64) или .pem в один общий текстовый файл cacert.pem.Даже после правильной настройки cacert.pem и использования клиентского .p12, проблема "400 The SSL certificate error" может сохраняться, указывая на то, что сервер всё ещё отклоняет наш клиентский сертификат. Давайте выясним наиболее вероятные причины этой ошибки:
СертификатКлиентаФайл, полностью совпадает с паролем, которым был защищен файл .p12..cer содержит только публичный ключ. Для клиентской авторизации необходим файл, содержащий и публичный ключ, и закрытый ключ (тот самый формат .p12 или .pfx). Если мы начинали с .cer и не смогли правильно получить .p12 с закрытым ключом, авторизация невозможна.ЗащищенноеСоединениеOpenSSL, который работает с файлами.В качестве обходного пути, мы можем рассмотреть использование утилиты stunnel. stunnel — это кроссплатформенный прокси-сервер, который может устанавливать SSL/TLS-соединения от вашего имени. Мы можем настроить stunnel на вашей локальной машине или на сервере 1С следующим образом:
stunnel для подключения к внешнему HTTP-сервису, используя наш клиентский SSL-сертификат и выполняя все необходимые SSL-рукопожатия. В конфигурации stunnel мы укажем путь к клиентскому сертификату и ключу, а также к файлам УЦ.stunnel по обычному HTTP (без SSL), указав в HTTPСоединение адрес и порт, на котором прослушивает stunnel. stunnel будет прозрачно перенаправлять трафик через защищенное соединение.Этот подход может быть полезен, если мы столкнулись с непреодолимыми трудностями при настройке SSL напрямую в 1С. Для организации других видов обмена данными, например, через WebSTOMP для RabbitMQ, могут потребоваться иные инструменты и протоколы.
Если встроенные средства 1С и OpenSSL не дают желаемого результата, наиболее эффективным и проверенным решением является использование системного COM-объекта WinHttp.WinHttpRequest.5.1. Этот объект предоставляет функциональность HTTP-клиента, которая использует встроенные механизмы Windows для работы с SSL/TLS, включая доступ к системным хранилищам сертификатов Windows.
Преимущество этого подхода в том, что если наш клиентский сертификат корректно установлен в хранилище сертификатов Windows, то WinHttp.WinHttpRequest.5.1 может автоматически его использовать. Похожие системные механизмы авторизации задействуются, когда выполняется интеграция 1С с Google Таблицами через сервисный аккаунт.
Для использования этого метода, выполним следующие шаги:
WinHttp.WinHttpRequest.5.1 в 1С.SetClientCertificate или свойство Option (с параметром WinHttpRequestOption_ClientCertificate), позволяющее выбрать сертификат по отпечатку или другим характеристикам.Давайте посмотрим на концептуальный пример кода для WinHttp.WinHttpRequest.5.1 (точный выбор сертификата по отпечатку может отличаться в зависимости от контекста и версии Windows):
// Создаем COM-объект WinHttpRequest
Попытка
WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
Исключение
Сообщить("Ошибка при создании COM-объекта WinHttp.WinHttpRequest.5.1: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Устанавливаем метод HTTP (POST, GET и т.д.), URL и асинхронность (Ложь - синхронный)
WinHttp.Open("POST", "https://fglrr-site.its/XAdES-TesT/Sign", Ложь);
// Устанавливаем необходимые заголовки запроса
WinHttp.SetRequestHeader("Content-Type", "text/xml; charset=utf-8");
// Для SOAP-сервисов часто требуется заголовок SOAPAction
// WinHttp.SetRequestHeader("SOAPAction", """http://sign.server.procertum.unizeto/requestSignXAdES""");
// Указываем клиентский сертификат.
// Если сертификат установлен в хранилище "Личные", WinHttp может автоматически
// выбрать подходящий сертификат, если он является единственным или настроен для домена.
// Для явного указания сертификата по отпечатку (Thumbprint) можно использовать
// метод SetClientCertificate. Отпечаток сертификата можно найти в свойствах сертификата
// в хранилище Windows.
// Пример:
// ИмяСертификата = "CN=My Client Certificate, O=My Org"; // Или отпечаток
// WinHttp.SetClientCertificate("CURRENT_USER\My\" + ИмяСертификата);
//
// Более гибкий способ - через свойства:
// Const WinHttpRequestOption_ClientCertificate = 13; // Код опции для клиентского сертификата
// Const CERT_SYSTEM_STORE_CURRENT_USER = 1;
// Const CERT_SYSTEM_STORE_LOCAL_MACHINE = 2;
//
// Мы можем перечислить сертификаты в хранилище и выбрать нужный по отпечатку
// или другим параметрам. Например, получим отпечаток заранее.
// ОтпечатокСертификата = "ВАШ_ОТПЕЧАТОК_СЕРТИФИКАТА_БЕЗ_ПРОБЕЛОВ"; // Пример: "4f11a43a011030e2381f5c6f0d1487d21d7b049b"
//
// Для получения отпечатка можно использовать:
// WinHttp.Option(WinHttpRequestOption_ClientCertificate) = "LOCAL_MACHINE\My\" + ОтпечатокСертификата; // Если сертификат в хранилище компьютера
// WinHttp.Option(WinHttpRequestOption_ClientCertificate) = "CURRENT_USER\My\" + ОтпечатокСертификата; // Если сертификат в хранилище текущего пользователя
//
// В простейшем случае, если сертификат единственный и подходящий, WinHttp может найти его сам.
// Для данной темы, поскольку автор смог решить проблему, вероятно, использовался
// либо автоматический выбор, либо отпечаток.
// Формируем тело запроса (как и для HTTPЗапроса)
СтрокаXML = "
|<s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/"">
| <s:Body xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.001/XMLSchema"">
| <requestSignXAdES xmlns=""http://sign.server.procertum.unizeto/"">
| <certificate xmlns="">%СертБасе64%</certificate>
| <contentType xmlns="">application/octet-stream</contentType>
| <data xmlns="">%данные%</data>
| <signatureType xmlns="">ENVELOPING</signatureType>
| <validationDataFormat xmlns="">XADES</validationDataFormat>
| </requestSignXAdES>
| </s:Body>
|</s:Envelope>";
// Предполагаем, что СертБасе64 уже сформирован, как в предыдущем примере
// СертДвоичнДанные = Новый ДвоичныеДанные("e:\Install\testq.cer");
// СертБасе64 = ПолучитьСертификатBase64Строку(СертДвоичнДанные);
// СтрокаXML = СтрЗаменить(СтрокаXML,"%СертБасе64%",СертБасе64);
// Отправляем запрос
WinHttp.Send(СтрокаXML);
// Получаем ответ и проверяем статус
Если WinHttp.Status = 200 Тогда
Сообщить("Успешно: " + WinHttp.ResponseText);
Иначе
Сообщить("Ошибка " + WinHttp.Status + ": " + WinHttp.StatusText);
Сообщить("Ответ сервера: " + WinHttp.ResponseText);
КонецЕсли;
Этот подход позволил автору темы успешно решить проблему с подключением, что подчеркивает его надежность для сложных сценариев SSL-аутентификации в 1С, особенно когда возникают несовместимости или ограничения с встроенными механизмами платформы.
Для успешной работы с клиентскими SSL-сертификатами в 1С, мы рекомендуем учитывать следующие аспекты:
ЗащищенноеСоединениеOpenSSL) клиентский сертификат должен быть в формате PKCS#12 (файлы .p12 или .pfx), содержащий закрытый ключ. Если у вас есть только публичный сертификат (.cer), его необходимо конвертировать вместе с закрытым ключом в этот формат.cacert.pem содержит сертификаты удостоверяющих центров, которым вы доверяете для проверки подлинности серверного сертификата. Если этот файл отсутствует или некорректен, вы получите ошибку "Удаленный узел не прошел проверку".Подводя итог, подключение к HTTP-сервисам с клиентскими SSL-сертификатами в 1С требует тщательной настройки и понимания принципов работы SSL/TLS. Если встроенные механизмы 1С вызывают трудности или требуют слишком много усилий для настройки, использование COMОбъект("WinHttp.WinHttpRequest.5.1") является проверенным и эффективным решением, использующим системные возможности Windows.