Как организовать подписание PDF неквалифицированной подписью со штампом на сервере 1С?

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

Перед многими разработчиками и системными архитекторами встает задача организации внутреннего электронного документооборота (ЭДО). Типичный сценарий: необходимо перевести внутренний документ (например, Акт списания или Перемещение ТМЦ) в формат PDF, подписать его неквалифицированной электронной подписью (НЭП) на стороне сервера и визуализировать эту подпись в виде красивого штампа непосредственно в теле документа. При этом бизнес часто ставит жесткое условие — решение должно быть максимально бюджетным или полностью бесплатным, без покупки серверных лицензий «КриптоПро CSP» (стоимость которых для сервера может быть весьма существенной).

В этой статье мы подробно разберем, как реализовать этот механизм, проанализируем различные подходы, рассмотрим готовые примеры кода на стороне 1С и обсудим важные архитектурные нюансы безопасности при подписании документов через СМС-подтверждение.

---

Вариант 1. Использование встроенных механизмов платформы 1С (для версий 8.3.16 и выше)

Начнем с самого современного и элегантного способа. Если ваша конфигурация работает на платформе 1С:Предприятие версии 8.3.16 или старше, вам больше не требуются сторонние утилиты для работы с PDF. Фирма 1С добавила мощный встроенный механизм для работы с PDF-документами, который позволяет программно добавлять подписи и визуальные штампы.

Для реализации этого подхода используются системные объекты ЗаписьPDF, ОписаниеПодписиPDF и МенеджерКриптографии. Давайте разберем по шагам, как настроить бесплатное серверное подписание на Windows с использованием стандартных криптопровайдеров ОС (без КриптоПро).

Посмотрим на пример кода, реализующий серверное подписание PDF-файла:


// Функция осуществляет подписание PDF файла встроенными средствами платформы
Функция ПодписатьPDFНаСервере(ПутьКФайлуИсточник, ПутьКФайлуРезультат, ИмяСертификатаВХранилище) Экспорт
    
    // Инициализируем менеджер криптографии. 
    // Используем стандартный системный криптопровайдер Windows (RSA), который бесплатен.
    МенеджерКрипт = Новый МенеджерКриптографии("", "", 1); // 1 - тип провайдера PROV_RSA_FULL
    
    // Поиск необходимого сертификата в системном хранилище "My" (Личные) на сервере
    ВыбранныйСертификат = Неопределено;
    Сертификаты = МенеджерКрипт.ПолучитьСертификатыИзХранилища("My");
    Для Каждого Сертификат Из Сертификаты Цикл
        Если Найти(Сертификат.Субъект, ИмяСертификатаВХранилище) > 0 Тогда
            ВыбранныйСертификат = Сертификат;
            Прервать;
        КонецЕсли;
    КонецЦикла;
    
    Если ВыбранныйСертификат = Неопределено Тогда
        ВызватьИсключение "Не найден подходящий сертификат в хранилище сервера!";
    КонецЕсли;
    
    // Настраиваем параметры визуального отображения штампа подписи
    ОписаниеПодписи = Новый ОписаниеПодписиPDF;
    ОписаниеПодписи.Имя = "ПодписьБухгалтера";
    ОписаниеПодписи.Страница = 1; // Номер страницы для размещения штампа (или ОписаниеПодписиPDF.ПоследняяСтраница)
    
    // Задаем координаты расположения штампа в пикселях
    ОписаниеПодписи.Лево = 50;
    ОписаниеПодписи.Низ = 100;
    ОписаниеПодписи.Ширина = 250;
    ОписаниеПодписи.Высота = 90;
    
    // Создаем визуальный макет штампа. В качестве макета можно использовать Табличный Документ 1С.
    ТабДокШтамп = Новый ТабличныйДокумент;
    // ... здесь можно программно заполнить ячейки макета: нарисовать рамку, вывести ФИО, дату, текст "ДОКУМЕНТ ПОДПИСАН" ...
    Область = ТабДокШтамп.Область("R1C1:R5C5");
    Область.Текст = "ДОКУМЕНТ ПОДПИСАН ЭП" + Символы.ПС + ВыбранныйСертификат.Субъект;
    Область.Обвести();
    
    ОписаниеПодписи.Отображение = ТабДокШтамп;
    
    // Производим чтение исходного файла и запись нового с наложением подписи
    ЗаписьPDF = Новый ЗаписьPDF;
    ЗаписьPDF.Открыть(ПутьКФайлуРезультат);
    
    // Передаем исходный документ, сертификат и настройки подписи
    ЗаписьPDF.Записать(ПутьКФайлуИсточник, ВыбранныйСертификат, ОписаниеПодписи);
    ЗаписьPDF.Закрыть();
    
    Возврат Истина;
КонецФункции

Преимущества данного способа: Полная автономность от стороннего ПО, отсутствие затрат на лицензии при работе на Windows (используется встроенный CryptoAPI), высокая скорость генерации, штамп встраивается непосредственно в структуру PDF.

---

Вариант 2. Использование бесплатной консольной утилиты PDFTK

Если сервер 1С работает под управлением Linux или вам требуется гибко управлять сложными визуальными слоями (например, «склеивать» несколько документов, динамически накладывать факсимиле подписи и печати поверх готового текста в строго определенные места), отличным решением будет использование консольной утилиты PDFTK (PDF Toolkit).

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

Рассмотрим пример реализации этой схемы на стороне сервера 1С:


Процедура НаложитьШтампЧерезPDFTK(ПутьКИсходномуPDF, ПутьКФайлуШтампа, ПутьКГотовомуPDF) Экспорт
    
    // Задаем путь к исполняемому файлу утилиты pdftk на сервере
    ПутьКПрограмме = """C:\Program Files (x86)\PDFtk Server\bin\pdftk.exe""";
    
    // Формируем параметры запуска. Команда "background" накладывает один PDF на другой как подложку.
    // Если нужно наложить поверх текста, используется команда "stamp".
    ПараметрыЗапуска = СтрШаблон("%1 ""%2"" stamp ""%3"" output ""%4""", 
                                  ПутьКПрограмме, 
                                  ПутьКИсходномуPDF, 
                                  ПутьКФайлуШтампа, 
                                  ПутьКГотовомуPDF);
    
    // Запускаем консольное приложение в скрытом режиме
    ЗапускПриложения(ПараметрыЗапуска, , Истина); // Третий параметр Истина означает ожидание завершения процесса
    
    // Проверяем результат
    ФайлРезультата = Новый Файл(ПутьКГотовомуPDF);
    Если Не ФайлРезультата.Существовать() Или ФайлРезультата.Размер() = 0 Тогда
        ВызватьИсключение "Ошибка генерации PDF: утилита PDFTK завершила работу некорректно.";
    КонецЕсли;
    
КонецПроцедуры

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


Процедура ПолучитьФайлСПодписями(НакопленныеДанные)
    
    Попытка
        ОпределитьВозможностьСклейкиСПодписями(НакопленныеДанные);
        Если НакопленныеДанные.МожноСклеить = Истина Тогда
            ПолучитьИзначальныйФайл(НакопленныеДанные);
            ПодготовитьСредствоРаботыСPDF(НакопленныеДанные);
            СгенерироватьФайлСлужебнойИнформации(НакопленныеДанные);
            ПолучитьИнтересующиеДанныеИзФайлаСлужебнойИнформации(НакопленныеДанные);
            СоздатьPDFСНумерацией(НакопленныеДанные);
            СоздатьPDFСПодписями(НакопленныеДанные);
            СклеитьФайлы(НакопленныеДанные);
            УдалитьВременныеФайлы(НакопленныеДанные);
        КонецЕсли;
    Исключение
        Сообщить("Ошибка выполнения операции с PDFTK: " + ОписаниеОшибки());
    КонецПопытки;
    
КонецПроцедуры

---

Вариант 3. Легковесный микросервис подписания (Python + pyHanko / Node.js)

Когда сервер 1С функционирует на операционной системе Linux, работа со стандартными Windows-криптопровайдерами невозможна, а установка КриптоПро требует затрат. В таких случаях идеальной архитектурной альтернативой является создание локального микросервиса на вашем сервере приложений.

Отличным решением будет развертывание небольшого веб-сервиса на Python с использованием библиотеки pyHanko (современный инструмент для создания PDF-подписей по стандарту PAdES) или библиотеки endesive. Сервер 1С будет отправлять по HTTP POST исходный файл PDF и файл сертификата (в формате PFX / P12 с паролем), а в ответ получать готовый подписанный PDF со штампом.

Примерная схема HTTP-запроса из 1С к такому сервису выглядит так:


Функция ОтправитьНаСервисПодписания(ПутьКФайлуPDF, ПутьКСертификатуPFX, ПарольКСертификату, АдресСервиса)
    
    // Читаем файлы в двоичные данные
    ДвоичныеДанныеPDF = Новый ДвоичныеДанные(ПутьКФайлуPDF);
    ДвоичныеДанныеPFX = Новый ДвоичныеДанные(ПутьКСертификатуPFX);
    
    // Формируем POST-запрос (Multipart form-data или JSON с кодированием в Base64)
    Разделитель = "----Boundary" + Формат(ТекущаяДата(), "ДФ=yyyyMMddhhmmss");
    
    ТелоЗапроса = Новый ТекстовыйДокумент;
    // ... формируем тело запроса, содержащее PDF и PFX файлы ...
    
    Запрос = Новый HTTPЗапрос(АдресСервиса);
    Запрос.УстановитьТелоИзДвоичныхДанных(ТелоЗапроса.ПолучитьДвоичныеДанные());
    Запрос.Заголовки.Вставить("Content-Type", "multipart/form-data; boundary=" + Разделитель);
    
    Соединение = Новый HTTPСоединение("localhost", 8080); // Порт нашего микросервиса
    Ответ = Соединение.ОтправитьДляОбработки(Запрос);
    
    Если Ответ.КодСостояния = 200 Тогда
        // Записываем полученный подписанный файл обратно на диск
        Ответ.ПолучитьТелоИзДвоичныхДанных().Записать(ПутьКФайлуPDF);
        Возврат Истина;
    Иначе
        ЗаписьЖурналаРегистрации("Подписание", УровеньЖурналаРегистрации.Ошибка, , , Ответ.ПолучитьТелоКакСтроку());
        Возврат Ложь;
    EndIf;
    
КонецФункции

---

Архитектурная безопасность: Схема подписания через СМС-код

Разберем важный методологический аспект, затронутый в обсуждении. При проектировании схемы «Пользователь нажимает кнопку в браузере -> Получает СМС -> Вводит код в 1С -> Сервер подписывает документ ключом, хранящимся на сервере» часто совершается критическая ошибка безопасности.

Проблема: Пользователь не контролирует, что именно он подписывает. В момент ввода СМС-кода сервер может теоретически подсунуть под подпись измененную версию PDF-файла (например, с другими суммами или реквизитами контрагента).

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

  1. Генерация хэш-суммы: Когда документ подготовлен к отправке, сервер 1С формирует финальный вариант PDF-файла и вычисляет его криптографический хэш (например, по алгоритму SHA-256).
  2. Отображение пользователю: Этот конкретный PDF-файл отправляется на экран пользователю в интерфейс 1С или портал (например, Битрикс24) для ознакомления.
  3. Связывание с СМС: В момент отправки СМС-сообщения код подтверждения жестко связывается в базе данных 1С с ранее вычисленным хэшем файла. При возможности, в текст СМС добавляется краткая информация (например: "Код 4839 для подписания Акта №125 на сумму 15000 руб.").
  4. Финальное сравнение: При вводе пользователем кода подтверждения сервер 1С берет текущий PDF-файл, заново рассчитывает его хэш-сумму и сравнивает её с хэшем, зафиксированным при отправке СМС. Если хэши совпадают, документ подписывается. Если файл претерпел изменения хотя бы на один байт — операция немедленно блокируется.

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

← На главную