Как подписать документ ЭЦП на клиенте в 1С и получить непосредственно подписанные данные?

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

При работе с электронными документами в 1С часто возникает необходимость подписать их электронной цифровой подписью (ЭЦП). Однако процесс подписания может быть нетривиальным, особенно когда требуется получить не просто факт успешного подписания, а сами «сырые» подписанные данные для дальнейшей обработки или передачи. Рассмотрим различные подходы к решению этой задачи, сосредоточившись на клиентском подписании и особенностях получения результата.

1. Почему не следует использовать серверное подписание без наличия ЭЦП на сервере

Вопрос безопасности данных критически важен, особенно когда нужно уберечь конструкторскую документацию от кражи конкурентами.

Первое, с чем мы сталкиваемся при попытке подписать документ, – это выбор между серверным и клиентским подписанием. Многие разработчики начинают с использования методов, предназначенных для серверного выполнения, таких как ЭлектроннаяПодписьСлужебныйВызовСервера.ВыполнитьНаСторонеСервера(). Однако, если секретные ключи ЭЦП пользователя хранятся на его рабочем месте (например, на токене или в реестре), то попытка выполнить подписание на сервере 1С вызовет ошибку, поскольку сервер не имеет доступа к закрытому ключу пользователя.

Причина проста: закрытый ключ ЭЦП должен храниться в безопасном месте и не должен покидать защищенную среду (токен, аппаратный модуль безопасности или защищенное хранилище на компьютере пользователя). Передача закрытого ключа на сервер или его использование сервером без явного разрешения и соответствующей инфраструктуры безопасности противоречит основным принципам работы с ЭЦП.

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

2. Использование стандартного клиентского функционала 1С: метод ЭлектроннаяПодписьКлиент.Подписать

Для подписания документов на клиентской стороне платформа 1С предоставляет специализированный модуль ЭлектроннаяПодписьКлиент, в котором ключевым методом является Подписать(). Этот метод предназначен для взаимодействия с криптографическими средствами, установленными на компьютере пользователя.

Разберем по шагам, как использовать этот метод:

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

    
    Парам = Новый Структура;
    ОписаниеДанных = Новый Структура;
    ОписаниеДанных.Вставить("Данные", Файл); // Здесь может быть ссылка на двоичные данные, строка или другое представление файла
    ОписаниеДанных.Вставить("Операция", "Подписание");
    ОписаниеДанные.Вставить("ЗаголовокДанных", "Подписание документа");
    

    Обратите внимание, что Файл здесь – это условное обозначение данных, которые мы хотим подписать. В зависимости от вашей задачи это может быть строка Base64, двоичные данные файла или ссылка на объект 1С, содержащий эти данные.

  2. Вызов метода подписания. Метод ЭлектроннаяПодписьКлиент.Подписать() является асинхронным. Это означает, что он не возвращает результат сразу же, а инициирует процесс подписания, который может занять некоторое время. По завершении операции (успешно или с ошибкой) результат будет передан в специальную процедуру-обработчик, которую мы указываем через объект ОписаниеОповещения.

    
    ЭлектроннаяПодписьКлиент.Подписать(ОписаниеДанных,,Новый ОписаниеОповещения("ПослеПодписанияДокумента", ЭтотОбъект, Парам));
    
  3. Обработка результата подписания. Результат операции подписи мы получаем в процедуре, указанной в ОписаниеОповещения. В нашем примере это процедура ПослеПодписанияДокумента.

    
    &НаКлиенте
    Процедура ПослеПодписанияДокумента(Результат, Параметры) Экспорт
        // Здесь выполняются действия с подписанным документом или обработка ошибки
        Если Результат.Успех Тогда
            Сообщить("Документ успешно подписан.");
            // Дальнейшая обработка. Но где же сами подписанные данные?
    КонецПроцедуры
        Иначе
            Сообщить("Ошибка подписания: " + Результат.ОписаниеОшибки);
        КонецЕсли;
    КонецПроцедуры
    

Особенности метода ЭлектроннаяПодписьКлиент.Подписать и получение результата

Мы выяснили, что ЭлектроннаяПодписьКлиент.Подписать() успешно выполняет операцию подписания на клиенте и уведомляет нас о результате через процедуру оповещения. Однако, если наша задача состоит в том, чтобы получить непосредственно «сырые» подписанные данные (например, строку с Base64-кодированной подписью или файл подписи), стандартный метод ЭлектроннаяПодписьКлиент.Подписать() может не предоставить эту информацию в явном виде в структуре Результат.

Как правило, в типовых конфигурациях 1С этот метод интегрируется с внутренними механизмами электронного документооборота. Он может сохранять подписанный документ во внутреннее хранилище, добавлять к нему электронную подпись как метаданные или подготавливать документ для отправки через ЭДО, но не всегда возвращает саму криптографическую подпись в виде отдельной строки или файла, готового для использования вне контекста 1С.

Именно эта особенность заставляет разработчиков искать альтернативные пути, когда требуется больший контроль над процессом подписания и форматом выходных данных.

3. Прямое получение подписанных данных: низкоуровневое подписание с использованием COM-объектов CAdESCOM

Если стандартный функционал 1С не удовлетворяет требованию по получению «сырых» подписанных данных, мы можем обратиться к низкоуровневой работе с криптографическими провайдерами через COM-обобъекты. Один из наиболее распространенных способов для Windows-клиентов – использование библиотеки CAdESCOM (или CAPICOM, ее предшественника).

CAdESCOM – это компонент, который предоставляет программный интерфейс для работы с электронной подписью по стандартам CAdES (Cryptographic Message Syntax Advanced Electronic Signatures). Это позволяет нам получить полный контроль над процессом подписания, включая выбор типа подписи (открепленная/прикрепленная), добавление атрибутов и, что важно, прямое получение результата в виде строки Base64.

Давайте рассмотрим пример функции, которая выполняет подписание текста с помощью CAdESCOM и возвращает подписанные данные:


// bDetached - Истина/Ложь - откреплённая(для подписания документов)/прикреплённая подпись
Функция CADESCOM_ПодписатьТекст(ТекстДляПодписи, ОтпечатокСертификата, bDetached, ЗашифроватьBase64=Истина) Экспорт

    // Константы для работы с CAdESCOM
    CADESCOM_CADES_TYPE = 1; // Тип усовершенствованной подписи (CAdES-BES)
    CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME = 0; // Атрибут штампа времени подписи

    Попытка
        // 1. Создание объекта для атрибута штампа времени
        oSigningTimeAttr = Новый COMОбъект("CAdESCOM.CPAttribute");
        oSigningTimeAttr.Name = CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME;
        oSigningTimeAttr.Value = ТекущаяДата(); // Устанавливаем текущую дату в качестве штампа

        // 2. Создание объекта подписанта
        oSigner = Новый COMОбъект("CAdESCOM.CPSigner");
        // Получение сертификата по отпечатку (предполагается наличие вспомогательной функции CADESCOM_СертификатПоОтпечатку)
        oSigner.Certificate = CADESCOM_СертификатПоОтпечатку(ОтпечатокСертификата);
        // Добавление атрибута штампа времени к подписи
        oSigner.AuthenticatedAttributes2.Add(oSigningTimeAttr);

        // 3. Создание объекта для работы с подписываемыми данными
        oSignedData = Новый COMОбъект("CAdESCOM.CadesSignedData");
        oSignedData.ContentEncoding = 1; // 1 означает, что входные данные пришли в Base64
        oSignedData.Content = СокрЛП(ТекстДляПодписи); // Устанавливаем данные для подписи

        // 4. Выполнение операции подписания
        // SignCades - метод для создания усовершенствованной подписи
        // Первый параметр - объект подписанта
        // Второй параметр - тип подписи (CADESCOM_CADES_TYPE)
        // Третий параметр - bDetached (открепленная/прикрепленная подпись)
        // Четвертый параметр - SecurityContext (обычно 0)
        РезультатПодписи = oSignedData.SignCades(oSigner, CADESCOM_CADES_TYPE, bDetached, 0);

        Если ЗашифроватьBase64 Тогда
            Возврат РезультатПодписи; // Подпись уже в формате Base64
        Иначе
            Возврат РезультатПодписи; // Или другая обработка, если не нужна Base64 строка
        КонецЕсли;

    Исключение
        ЗаписьЖурналаРегистрации(
            "ОшибкаПодписанияCAdESCOM",
            УровеньЖурналаРегистрации.Ошибка,
            ,,
            "Ошибка при подписании данных с использованием CAdESCOM: " + ОписаниеОшибки()
        );
        Возврат Неопределено;
    КонецПопытки;

КонецФункции

// Пример вспомогательной функции для получения сертификата по отпечатку
Функция CADESCOM_СертификатПоОтпечатку(ОтпечатокСертификата)
    oStore = Новый COMОбъект("CAdESCOM.Store");
    oStore.Open(); // Открываем хранилище сертификатов
    oCertificates = oStore.Certificates;
    oCertificates.Find(0, ОтпечатокСертификата); // Ищем сертификат по отпечатку (CAPICOM_CERTIFICATE_FIND_SHA1_HASH = 0)
    Если oCertificates.Count > 0 Тогда
        Возврат oCertificates.Item(1); // Возвращаем первый найденный сертификат
    Иначе
        ВызватьИсключение "Сертификат с отпечатком " + ОтпечатокСертификата + " не найден.";
    КонецЕсли;
    oStore.Close();
КонецФункции

Пошаговый разбор функции CADESCOM_ПодписатьТекст

Давайте подробно рассмотрим, что происходит в этой функции, и как каждый шаг способствует получению желаемого результата:

  1. Константы и инициализация: Мы определяем константы CADESCOM_CADES_TYPE (для типа подписи CAdES-BES, который является базовым для усовершенствованной подписи) и CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME (для добавления атрибута времени подписания).

  2. Добавление атрибута штампа времени: Мы создаем объект CAdESCOM.CPAttribute. Атрибуты подписи – это дополнительная информация, которая включается в саму подпись и может содержать, например, время подписания, политику подписи и другие данные. Добавление штампа времени повышает юридическую значимость подписи, так как позволяет зафиксировать момент подписания.

    
    oSigningTimeAttr = Новый COMОбъект("CAdESCOM.CPAttribute");
    oSigningTimeAttr.Name = CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME;
    oSigningTimeAttr.Value = ТекущаяДата();
    
  3. Объект подписанта (CAdESCOM.CPSigner): Этот объект представляет собой сущность, которая будет выполнять подписание. Мы привязываем к нему сертификат пользователя (полученный, например, по его отпечатку) и добавляем все необходимые атрибуты (в нашем случае – штамп времени).

    
    oSigner = Новый COMОбъект("CAdESCOM.CPSigner");
    oSigner.Certificate = CADESCOM_СертификатПоОтпечатку(ОтпечатокСертификата);
    oSigner.AuthenticatedAttributes2.Add(oSigningTimeAttr);
    

    Функция CADESCOM_СертификатПоОтпечатку() является вспомогательной и демонстрирует, как можно найти нужный сертификат в хранилище пользователя по его уникальному отпечатку (SHA1-хешу).

  4. Подготовка данных для подписи (CAdESCOM.CadesSignedData): Объект CAdESCOM.CadesSignedData – это ключевой элемент, который будет работать непосредственно с данными и генерировать подпись. Мы устанавливаем его свойства:

    • oSignedData.ContentEncoding = 1;: Это очень важный параметр. Значение 1 указывает, что данные, передаваемые для подписи в свойстве Content, уже находятся в формате Base64. Если бы мы передавали "сырые" двоичные данные, то этот параметр был бы другим.
    • oSignedData.Content = СокрЛП(ТекстДляПодписи);: Сюда мы передаем подготовленные данные (текст или Base64-строку бинарных данных), которые нужно подписать.
    
    oSignedData = Новый COMОбъект("CAdESCOM.CadesSignedData");
    oSignedData.ContentEncoding = 1;
    oSignedData.Content = СокрЛП(ТекстДляПодписи);
    
  5. Выполнение подписи (oSignedData.SignCades()): Непосредственно операция подписания. Метод SignCades() принимает несколько параметров:

    • Первый параметр (oSigner) – объект подписанта, который мы подготовили ранее.
    • Второй параметр (CADESCOM_CADES_TYPE) – тип усовершенствованной подписи (например, CAdES-BES).
    • Третий параметр (bDetached) – определяет, будет ли подпись открепленной (Истина) или прикрепленной (Ложь).
      • Открепленная подпись: Создается отдельный файл подписи (обычно с расширением .sig), а исходный документ остается неизменным. Это удобно, когда исходный документ должен быть доступен для чтения без специального ПО.
      • Прикрепленная подпись: Сама подпись включается в исходный документ, изменяя его структуру. Такой документ содержит как данные, так и подпись.
    • Четвертый параметр (0) – контекст безопасности, обычно используется значение 0.
    
    РезультатПодписи = oSignedData.SignCades(oSigner, CADESCOM_CADES_TYPE, bDetached, 0);
    

    Метод возвращает строку Base64, содержащую сгенерированную подпись, что и является тем "подписанным файлом" или "подписанными данными", которые мы ищем.

  6. Возврат результата: Функция возвращает полученную Base64-строку подписи.

Подготовка данных для подписания: что такое "ТекстДляПодписи"?

Вопрос о том, откуда берется "ТекстДляПодписи", является критически важным. Метод CAdESCOM.CadesSignedData.Content ожидает получить данные, которые будут подписаны. Это может быть:

  1. Простой текст: Если вы подписываете обычную текстовую строку, то ее можно передать напрямую.

  2. Бинарные данные (файлы): Если вы хотите подписать файл (например, PDF, изображение, архив), то эти бинарные данные необходимо предварительно преобразовать в текстовый формат. Наиболее распространенный способ – это кодирование в Base64. В этом случае, перед вызовом функции CADESCOM_ПодписатьТекст, вы должны:

    1. Прочитать содержимое файла в двоичные данные.
    2. Преобразовать двоичные данные в строку Base64.
    3. Эту Base64-строку передать в параметр ТекстДляПодписи.

    Например, в 1С для преобразования двоичных данных в Base64 можно использовать функцию Base64Кодировать() или специализированные обработки для кодирования Base64 через потоки.

    
    // Пример: чтение файла и кодирование в Base64
    ИмяФайла = "C:\МойДокумент.pdf";
    ДвоичныеДанныеФайла = Новый ДвоичныеДанные(ИмяФайла);
    ТекстДляПодписиВBase64 = Base64Кодировать(ДвоичныеДанныеФайла);
    
    // Затем вызываем функцию подписания
    ПодписанныеДанные = CADESCOM_ПодписатьТекст(ТекстДляПодписиВBase64, ОтпечатокСертификата, Истина);
    

    Настройка oSignedData.ContentEncoding = 1; в функции CADESCOM_ПодписатьТекст как раз и говорит библиотеке CAdESCOM, что содержимое, которое ей передается (oSignedData.Content), уже является Base64-строкой.

4. Настройка 1С и криптопровайдера для работы с ЭЦП

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

  1. Включение функционала ЭЦП в 1С: В конфигурации 1С (обычно в разделе "Администрирование – Электронная подпись и шифрование") должен быть установлен флажок "Электронная подпись". Это активирует встроенные механизмы работы с ЭЦП.

  2. Установка криптопровайдера: На клиентском компьютере должен быть установлен криптопровайдер (например, КриптоПро CSP или средства для работы с ID-картами) и необходимые сертификаты ЭЦП, включая закрытый ключ, который может храниться на USB-токене или в реестре.

  3. Расширение для работы с криптографией: Для работы в веб-клиенте 1С, а также для корректного взаимодействия с криптопровайдером, требуется установка специального расширения для работы с криптографией в браузере и компоненты для работы с криптографией от 1С.

  4. Регистрация COM-объектов: При использовании CAdESCOM убедитесь, что компоненты CAdESCOM (например, КриптоПро ЭЦП Browser plug-in) установлены и зарегистрированы в системе. Обычно это происходит автоматически при установке плагина КриптоПро. Если вы используете COMОбъект(), то система должна иметь возможность найти и создать этот объект.

Заключение

Мы рассмотрели два основных подхода к подписанию документов ЭЦП на клиентской стороне в 1С. Стандартный метод ЭлектроннаяПодписьКлиент.Подписать() удобен для интеграции с типовым документооборотом 1С, но может не предоставлять прямой доступ к "сырой" строке подписи. Для получения полного контроля над процессом подписания и непосредственного извлечения подписанных данных, включая выбор формата подписи (открепленная/прикрепленная), рекомендуется использовать низкоуровневый подход с COM-объектами CAdESCOM. Выбор метода зависит от ваших конкретных требований к формату подписи и дальнейшей обработке подписанных данных.

← На главную