Как настроить авторизацию в API Честного Знака из 1С и программно подписывать запросы УКЭП?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Интеграция систем 1С с государственной информационной системой маркировки товаров (ГИС МТ / «Честный Знак») — одна из наиболее частых задач при автоматизации торговых и производственных предприятий. Основная сложность, с которой сталкиваются разработчики при работе с True API «Честного Знака», заключается в прохождении криптографической авторизации. Для получения токена доступа система требует подписать случайную строку данных с помощью усиленной квалифицированной электронной подписи (УКЭП) организации.

В этой статье мы подробно разберем, как устроен процесс авторизации, почему стандартные методы 1С в старых версиях платформы вызывают ошибки, как реализовать подписание с помощью внешней компоненты, а также как решать эти задачи на современных версиях платформы 1С:Предприятие.

Общая схема авторизации в API «Честного Знака»

Процесс получения доступа к методам API состоит из трех основных шагов:

  1. Получение данных для подписания. Наше решение отправляет GET-запрос к API на адрес /api/v3/auth/cert/key (или аналогичный метод используемой версии True API). В ответ сервер возвращает уникальный идентификатор сессии (uuid) и случайную строку данных в формате Base64 (data).
  2. Подписание данных на стороне 1С. Полученную строку данных необходимо подписать закрытым ключом УКЭП. Важнейший нюанс, о котором часто спотыкаются разработчики: подпись должна быть присоединенной (Enveloped/Attached), то есть исходные данные должны быть упакованы внутрь результирующего криптографического контейнера PKCS#7.
  3. Отправка подписанных данных для получения токена. Подписанный массив данных, закодированный в Base64, отправляется POST-запросом обратно на сервер на адрес /api/v3/auth/cert/ (или метод simpleSignIn). Если подпись верна, сервер возвращает авторизационный токен.

Давайте подробно разберем, как преодолеть технические препятствия на каждом этапе.

Проблема присоединенной подписи в 1С и ее причины

При использовании стандартного объекта платформы 1С МенеджерКриптографии разработчики часто сталкиваются с ошибкой со стороны «Честного Знака»: «Ошибка при проверке подписи». Выясним причину этой проблемы.

Дело в том, что метод МенеджерКриптографии.Подписать() в старых версиях платформы 1С (до версии 8.3.26) генерировал исключительно отсоединенную (Detached) электронную подпись. При отсоединенной подписи создается отдельный файл подписи, который не содержит в себе подписываемые данные. API «Честного Знака» не может валидировать такую подпись, так как ожидает стандартный криптографический контейнер PKCS#7 (CMS), содержащий внутри себя и подпись, и само исходное тело сообщения.

Ниже мы рассмотрим два способа решения этой проблемы: классический (для старых платформ через внешнюю компоненту) и современный (штатными средствами новых версий платформы 1С).

Решение №1: Использование внешней компоненты XMLDSignAddIn (для старых платформ)

Если ваша конфигурация работает на платформе ниже 8.3.26 и не содержит встроенной Библиотеки Стандартных Подсистем (БСП) актуальной версии, оптимальным решением является использование внешней компоненты XMLDSignAddIn (ее можно извлечь из типовых конфигураций, например, Управление торговлей 11, Комплексная автоматизация или ERP).

Проанализируем готовый рабочий код авторизации с использованием этой компоненты:


// 1. Инициализируем соединение со стендом ГИС МТ
ИнтеграционныйСтенд = "int01.gismt.crpt.tech"; // Тестовый контур True API
Соединение = Новый HTTPСоединение(ИнтеграционныйСтенд, , , , , , Новый ЗащищенноеСоединениеOpenSSL);

// 2. Запрашиваем случайные данные для подписи
HTTPЗапрос = Новый HTTPЗапрос("/api/v3/auth/cert/key");
HTTPОтвет = Соединение.ВызватьHTTPМетод("GET", HTTPЗапрос);    
СтрокаJSON = HTTPОтвет.ПолучитьТелоКакСтроку();

ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(СтрокаJSON);
СтруктураДанных = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();

// В СтруктураДанных теперь содержатся uuid и data (случайная строка в Base64)

// 3. Получаем сертификат из локального хранилища операционной системы
МенеджерКриптографии = Новый МенеджерКриптографии("Crypto-Pro GOST R 34.10-2012 Cryptographic Service Provider", "", 80);
Хранилище = МенеджерКриптографии.ПолучитьХранилищеСертификатов();
СертификатыХранилища = Хранилище.ПолучитьВсе();

// Для примера берем первый подходящий сертификат
Сертификат = СертификатыХранилища[0]; 

// 4. Подключаем внешнюю компоненту для создания присоединенной подписи
МакетКомпоненты = ПолучитьМакетНаСервере(); // Макет, содержащий XMLDSignAddIn.zip или dll
АдресВХ = ПоместитьВоВременноеХранилище(МакетКомпоненты);    
Если ПодключитьВнешнююКомпоненту(АдресВХ, "XMLDSignAddInSymbolicName", ТипВнешнейКомпоненты.Native) Тогда
    Попытка
        ОбъектКомпоненты = Новый("AddIn.XMLDSignAddInSymbolicName.XMLDSignAddIn");
    Исключение
        ВызватьИсключение "Не удалось инициализировать внешнюю компоненту шифрования!";
    КонецПопытки;        
КонецЕсли;    

ОбъектКомпоненты.ПутьККриптопровайдеру = "";
// Выгружаем сертификат в Base64 для передачи в компоненту
СертификатBase64 = ПолучитьСтрокуBase64ИзДвоичныхДанных(Сертификат.Выгрузить());    

// 5. Формируем присоединенную подпись CMS посредством метода CMSSign
Попытка
    SignatureValue = ОбъектКомпоненты.CMSSign(
        СтруктураДанных.data,       // Исходные данные в формате строки
        СертификатBase64,           // Сертификат в формате Base64
        "",                         // Пароль к контейнеру закрытого ключа (если требуется)
        0,                          // Тип подписи (0 соответствует "CAdES-BES")
        Ложь,                       // Ложь — признак присоединенной подписи
        17,                         // Режим включения сертификатов (включать полную цепочку)
        0                           // Тип входных данных (0 — Строка)
    );
Исключение
    ВызватьИсключение "Ошибка вызова метода CMSSign: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
КонецПопытки;    

// Декодируем результат работы компоненты
ПодписьДД = ПолучитьДвоичныеДанныеИзСтроки(SignatureValue);

// Обязательно убираем символы перевода строк, если они присутствуют в Base64-представлении подписи
СтрокаПодписиBase64 = СтрЗаменить(ПолучитьСтрокуBase64ИзДвоичныхДанных(ПодписьДД), Символы.ПС, "");
СтрокаПодписиBase64 = СтрЗаменить(СтрокаПодписиBase64, Символы.ВК, "");

// 6. Подготавливаем структуру запроса для авторизации
СтруктураОтвета = Новый Структура;
СтруктураОтвета.Вставить("uuid", СтруктураДанных.uuid);
СтруктураОтвета.Вставить("data", СтрокаПодписиBase64);

ЗаписьJSON = Новый ЗаписьJSON;
ЗаписьJSON.УстановитьСтроку();
ЗаписатьJSON(ЗаписьJSON, СтруктураОтвета);
ТелоЗапроса = ЗаписьJSON.Закрыть();

// 7. Отправляем подписанные данные на сервер для получения токена
Заголовки = Новый Соответствие;    
Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
HTTPЗапросАвторизации = Новый HTTPЗапрос("/api/v3/auth/cert", Заголовки);    
HTTPЗапросАвторизации.УстановитьТелоИзСтроки(ТелоЗапроса);

Попытка
    HTTPОтветАвторизации = Соединение.ВызватьHTTPМетод("POST", HTTPЗапросАвторизации);    
Исключение
    ВызватьИсключение "Ошибка сетевого соединения при отправке подписи: " + ОписаниеОшибки();
КонецПопытки;

Если HTTPОтветАвторизации.КодСостояния = 200 Тогда
    СтрокаТокенаJSON = HTTPОтветАвторизации.ПолучитьТелоКакСтроку();
    ЧтениеТокена = Новый ЧтениеJSON;
    ЧтениеТокена.УстановитьСтроку(СтрокаТокенаJSON);
    РезультатАвторизации = ПрочитатьJSON(ЧтениеТокена);
    ЧтениеТокена.Закрыть();
    
    // Токен успешно получен!
    ТокенДоступа = РезультатАвторизации.token;
Иначе
    Сообщить("Авторизация не пройдена. Код ответа сервера: " + HTTPОтветАвторизации.КодСостояния);
КонецЕсли;

Данный алгоритм позволяет успешно обойти ограничение старых версий 1С и получить валидный токен авторизации.

Решение №2: Нативная присоединенная подпись в новых версиях платформы 1С

Рассмотрим, как изменилась ситуация с развитием платформы 1С:Предприятие. Начиная с версии 1С:Предприятие 8.3.26, разработчикам больше не требуется использовать внешние компоненты, DLL-библиотеки или сложные обходные маневры для интеграции с ГИС МТ.

В объект МенеджерКриптографии было добавлено новое стандартное свойство — ВключениеДанныхВПодпись. При установке этого свойства в значение Истина, платформа автоматически формирует присоединенную подпись в соответствии со всеми криптографическими стандартами PKCS#7 / CMS.

Посмотрим на пример лаконичного и современного кода для новых платформ:


// Инициализируем менеджер криптографии
Менеджер = Новый МенеджерКриптографии();

// Указываем платформе, что данные должны быть упакованы внутрь подписи
Менеджер.ВключениеДанныхВПодпись = Истина; 

// Получаем двоичные данные исходной строки, присланной сервером Честного Знака
ДанныеДляПодписи = ПолучитьДвоичныеДанныеИзСтроки(СтруктураДанных.data, КодировкаТекста.UTF8);

// Подписываем данные. Метод вернет присоединенную подпись в виде двоичных данных
ПрисоединеннаяПодписьДД = Менеджер.Подписать(ДанныеДляПодписи, Сертификат);

// Кодируем результат в Base64 для передачи в JSON-запрос
СтрокаПодписиBase64 = ПолучитьСтрокуBase64ИзДвоичныхДанных(ПрисоединеннаяПодписьДД);
СтрокаПодписиBase64 = СтрЗаменить(СтрЗаменить(СтрокаПодписиBase64, Символы.ПС, ""), Символы.ВК, "");

Использование этого встроенного механизма значительно упрощает поддержку кода, повышает скорость его работы на сервере и исключает возможные проблемы совместимости внешних компонент с различными операционными системами (например, при миграции сервера 1С на Linux). Наглядный пример реализации можно изучить через обработку для подписи произвольных файлов средствами платформы 1С.

Настройка работы криптографии на Сервере 1С

Если обмен с API «Честного Знака» выполняется в регламентных заданиях на сервере, возникает важный архитектурный вопрос: как подписывать запросы без участия пользователя?

Для автоматической подписи документов и запросов на сервере необходимо учесть следующие системные требования:

  1. Установка СКЗИ на сервере. Программа КриптоПро CSP должна быть физически установлена на том сервере, где запущена служба Сервера 1С:Предприятие.
  2. Права доступа. Сертификат электронной подписи и закрытый ключ должны быть установлены в операционной системе сервера под той учетной записью, от имени которой запущена служба usr1cv8. Если сертификат установлен в профиль администратора, серверная служба 1С просто не «увидит» закрытый ключ и выдаст ошибку прав доступа.
  3. Использование МЧД (Машиночитаемых доверенностей). В соответствии с современным законодательством, если регламентные задания подписывают запросы сертификатом физического лица (сотрудника), в Личном кабинете «Честного Знака» предварительно должна быть зарегистрирована и подтверждена соответствующая МЧД.

Альтернативный вариант, позволяющий избежать установки закрытых ключей на рабочий сервер — это генерация токена авторизации на стороне клиента (где локально подключен токен директора или сотрудника) один раз в день. Сгенерированный токен (время жизни которого составляет до 10 часов) может быть записан в общую константу или регистр сведений, откуда его будут считывать серверные фоновые задания для выполнения текущих операций обмена. Для дальнейшей работы с полученным доступом подойдёт обработка для запроса информации о кодах маркировки в Честном Знаке.

← На главную