При интеграции 1С с современными веб-сервисами (например, ГИС МТ «Честный ЗНАК», МДЛП или личными кабинетами различных ведомств) разработчики часто сталкиваются с необходимостью программной авторизации по сертификату ЭЦП. Типичный сценарий выглядит так: мы получаем от сервера некую строку данных (Data/Nonce/UUID), подписываем её закрытым ключом сертификата, кодируем результат в Base64 и отправляем обратно для получения токена доступа.
Однако стандартный объект 1С МенеджерКриптографии часто выдает результат, который сервер не принимает. Проанализируем, почему это происходит, и рассмотрим правильные способы формирования подписи, которые гарантированно пройдут проверку.
Основная причина расхождений при подписании данных в 1С заключается в различии стандартов криптографии. Рассмотрим подробнее ситуацию: стандартный метод МенеджерКриптографии.Подписать() по умолчанию формирует подпись в формате CMS (PKCS#7). В то же время большинство современных API требуют формат CAdES-BES или CAdES-T.
Хотя внешне оба формата выглядят как нечитаемая строка Base64, их внутренняя структура (ASN.1 дерево) существенно отличается. CAdES — это усовершенствованная подпись, которая включает в себя дополнительные атрибуты (например, время подписания). Если сервер ожидает CAdES-BES, а получает CMS, авторизация будет отклонена с ошибкой "Unauthorized".
Второй важный момент — присоединенная и отсоединенная подписи. Метод Подписать() в 1С создает присоединенную подпись, в которую упаковываются и исходные данные. Веб-сервисы же чаще всего ждут отсоединенную (detached) подпись, где передается только сам "отпечаток" подписи без исходного текста.
Для корректной работы с алгоритмами КриптоПро в 1С наиболее надежным способом является использование библиотеки CAdESCOM, которая устанавливается вместе с плагином КриптоПро ЭЦП Browser plug-in. Этот метод позволяет гибко управлять типом подписи и её параметрами.
Разберем по шагам процесс подписания данных для API. Сначала нам необходимо инициализировать объекты для работы с сертификатом и самой подписью. Проанализируем следующий пример кода:
// Функция принимает строку данных для подписи и отпечаток сертификата
Функция ПодписатьДанныеДляAPI(ДанныеДляПодписи, ОтпечатокСертификата) Экспорт
// Создаем объект для работы с параметрами подписи
Попытка
Signer = Новый COMОбъект("CAdESCOM.CPSigner");
Исключение
Сообщить("Не удалось создать объект CAdESCOM.CPSigner. Проверьте установку КриптоПро ЭЦП Browser plug-in.");
Возврат Неопределено;
КонецПопытки;
// Ищем сертификат в хранилище по отпечатку
Сертификат = НайтиСертификатПоОтпечатку(ОтпечатокСертификата);
Если Сертификат = Неопределено Тогда
ВызватьИсключение "Сертификат с указанным отпечатком не найден в хранилище 'Личные'!";
КонецЕсли;
Signer.Certificate = Сертификат;
// Указываем тип кодирования (0 - CAPICOM_ENCODE_BASE64, 1 - CAPICOM_ENCODE_BINARY)
// Для большинства API лучше использовать двоичные данные внутри, а результат получать в Base64
// Создаем объект для формирования подписи
SignedData = Новый COMОбъект("CAdESCOM.CadesSignedData");
SignedData.Content = ДанныеДляПодписи;
// Параметры метода SignCades:
// 1. Signer - объект с сертификатом
// 2. Тип подписи (1 = CADESCOM_CADES_BES)
// 3. Флаг отсоединенной подписи (Истина = Detached, Ложь = Attached)
// 4. Тип кодировки результата (0 = Base64)
ТипПодписи = 1; // CAdES-BES
ОтсоединеннаяПодпись = Истина;
КодировкаРезультата = 0; // BASE64
Попытка
РезультатПодписи = SignedData.SignCades(Signer, ТипПодписи, ОтсоединеннаяПодпись, КодировкаРезультата);
// Важно: убираем лишние переносы строк, которые может добавить COM-объект
РезультатПодписи = СтрЗаменить(РезультатПодписи, Символы.ПС, "");
РезультатПодписи = СтрЗаменить(РезультатПодписи, Символы.ВК, "");
Возврат РезультатПодписи;
Исключение
Сообщить("Ошибка при подписании: " + ОписаниеОшибки());
Возврат Неопределено;
КонецПопытки;
КонецФункции
Для работы CAdESCOM необходимо передать ему объект сертификата. Рассмотрим, как программно найти нужный сертификат в хранилище "Личные" (Personal) по его отпечатку (Thumbprint):
Функция НайтиСертификатПоОтпечатку(Отпечаток)
Store = Новый COMОбъект("CAdESCOM.Store");
// Открываем хранилище личных сертификатов текущего пользователя
Store.Open(2, "My", 0); // 2 = CAPICOM_CURRENT_USER_STORE, 0 = CAPICOM_STORE_OPEN_READ_ONLY
// Фильтруем сертификаты по отпечатку
НайденныеСертификаты = Store.Certificates.Find(0, Отпечаток); // 0 = CAPICOM_CERTIFICATE_FIND_SHA1_HASH
Если НайденныеСертификаты.Count = 0 Тогда
Store.Close();
Возврат Неопределено;
КонецЕсли;
ВыбранныйСертификат = НайденныеСертификаты.Item(1);
Store.Close();
Возврат ВыбранныйСертификат;
КонецФункции
Проанализируем ситуацию, когда даже при использовании CAdESCOM подпись не проходит проверку. Часто проблема кроется в подготовке исходных данных. Если API ожидает строку в кодировке UTF-8 без BOM, а вы передаете данные в другом формате, хэш-сумма будет неверной.
Выясним причину: 1С при работе с двоичными данными может добавлять метку BOM (Byte Order Mark). Чтобы этого избежать, при получении двоичных данных из строки следует явно указывать кодировку и проверять, не добавились ли лишние байты в начало массива. Однако при использовании свойства SignedData.Content для простых строк, COM-объект обычно корректно обрабатывает кодировку системы. Если же API требует подписи "сырых" байтов, данные лучше загружать через SignedData.ContentEncoding = 1 (Binary).
Рассмотрим важный аспект: где должен выполняться код подписания? Если код выполняется на стороне клиента (в тонком клиенте), то используются сертификаты и лицензия КриптоПро, установленные на рабочем месте пользователя. Это самый простой вариант.
Если же подписание должно происходить на сервере 1С (например, в фоновом задании), необходимо учитывать следующие требования:
Если работа с COM-объектами в серверном контексте вызывает сложности с правами доступа, проанализируем альтернативный вариант — использование консольной утилиты cryptcp.exe. Она поставляется вместе с КриптоПро и позволяет выполнить подписание через КомандаСистемы.
Этот метод часто оказывается более стабильным для серверных процессов. Мы записываем данные во временный файл, вызываем утилиту и считываем файл подписи:
// Пример формирования команды для консольной утилиты
Команда = "cryptcp -sign -detached -der -thumbprint " + Отпечаток + " " + ПутьКФайлуДанных + " " + ПутьКФайлуПодписи;
ЗапуститьПриложение(Команда,, Истина); // Ожидаем завершения
После этого остается только прочитать ПутьКФайлуПодписи, перевести двоичные данные в Base64 и отправить в теле POST-запроса. Помните, что при передаче подписи в JSON-запросе, она не должна содержать символов переноса строки, поэтому всегда используйте СтрЗаменить для очистки результирующей строки.
Таким образом, для успешной авторизации через API с использованием КриптоПро в 1С следует отказаться от стандартного МенеджерКриптографии в пользу CAdESCOM или cryptcp, обеспечивая формирование подписи в формате CAdES-BES (detached), и внимательно следить за отсутствием лишних символов в итоговой Base64 строке.