При автоматизации документооборота часто возникает задача последовательного подписания PDF-документа несколькими ответственными лицами. Основная сложность заключается в том, что по требованиям ГОСТ на документе часто должна присутствовать визуальная отметка (штамп) о совершенном подписании. Однако любое изменение файла (например, вставка картинки штампа) после наложения электронной подписи приводит к её повреждению. В этой статье мы разберем, как реализовать механизм добавления множественных штампов ЭЦП, используя штатные средства платформы 1С:Предприятие 8.3.
Для начала проанализируем ситуацию: почему обычное редактирование PDF убивает подпись? Любая электронная подпись (ЭЦП) гарантирует неизменность документа. Если мы открываем файл как картинку, рисуем на нем штамп и сохраняем — контрольная сумма файла меняется, и первая подпись становится невалидной.
Решение кроется в использовании технологии присоединенной подписи внутри структуры PDF. Формат PDF поддерживает так называемое инкрементальное сохранение (Incremental Updates). Когда мы добавляем подпись через специализированные объекты 1С, платформа не перезаписывает файл целиком, а дописывает данные о новой подписи и её визуальном представлении в конец файла. При проверке программы (например, Adobe Reader или КриптоПро PDF) умеют «отматывать» состояние файла к моменту наложения каждой конкретной подписи, подтверждая валидность всех этапов подписания.
Для реализации многократного подписания в 1С используются объекты ОписаниеПодписиPDF и ЗаписьPDF. Рассмотрим подробнее, как подготовить структуру для подписания. Основная логика заключается в том, что штамп не рисуется отдельно, а является частью визуального представления самой подписи.
Разберем по шагам процесс добавления подписи со штампом:
ОписаниеПодписиPDF.ЗаписатьПодпись (или его асинхронный аналог) объекта ЗаписьPDF.Проанализируем пример кода для формирования описания подписи:
ОписаниеПодписи = Новый ОписаниеПодписиPDF;
ОписаниеПодписи.Имя = "Подпись_" + ТекущийПользователь.Наименование;
ОписаниеПодписи.Страница = 1; // Указываем номер страницы, где будет штамп
ОписаниеПодписи.Лево = 50; // Координаты штампа
ОписаниеПодписи.Низ = 100;
ОписаниеПодписи.Ширина = 150;
ОписаниеПодписи.Высота = 50;
// Указываем данные сертификата для визуализации в штампе
ОписаниеПодписи.Текст = "Документ подписан ЭЦП" + Символы.ПС +
"Владелец: " + ФИОСотрудника + Символы.ПС +
"Сертификат: " + НомерСертификата;
Теперь выясним, как правильно применить это описание к существующему файлу. Если документ уже содержит одну или несколько подписей, нам нужно открыть его для чтения и дозаписать новую подпись. Важно понимать, что при использовании ЗаписьPDF предыдущие подписи сохраняются, если вы правильно работаете с объектом.
Запись = Новый ЗаписьPDF;
// Открываем существующий файл, который уже может содержать подписи
Запись.Открыть(ПутьКФайлу);
// Добавляем новую подпись с использованием сертификата и описания
Запись.ЗаписатьПодпись(СертификатКриптографии, ОписаниеПодписи);
// Файл будет обновлен инкрементально, сохранив старые данные
Запись.Закрыть();
Как показывает практика, при работе в веб-клиенте часто возникают ошибки типа «Неправильный путь к файлу» или просто отсутствие реакции системы. Это связано с тем, что веб-браузеры жестко ограничивают синхронные операции с файловой системой. Разберем ситуацию: если в тонком клиенте синхронные методы работают, то для веб-клиента обязательно использование асинхронных методов.
Рассмотрим правильный подход для кроссплатформенной работы:
// Сначала асинхронно открываем PDF для чтения
Чтение = Новый ЧтениеPDF;
Ждать Чтение.ОткрытьАсинх(ПутьКФайлу);
// Затем подготавливаем запись и асинхронно записываем подпись
Запись = Новый ЗаписьPDF;
Ждать Запись.ОткрытьАсинх(ПутьКВыходномуФайлу);
// Используем асинхронный метод для наложения подписи
Ждать Запись.ЗаписатьПодписьАсинх(Сертификат, ОписаниеПодписи);
Важный нюанс: Если вы забудете использовать ОткрытьАсинх и примените только ЗаписатьПодписьАсинх, в веб-клиенте это может привести к непредсказуемым ошибкам или зависанию сессии без выдачи сообщения об ошибке.
После того как мы научились добавлять подписи, нам может потребоваться программно проверить их наличие и валидность. В 1С объект ЧтениеPDF позволяет получить коллекцию подписей документа. Однако здесь есть «подводный камень»: при обращении к свойствам сертификата напрямую из объекта подписи PDF, система может зависнуть.
Для надежной проверки рекомендуется использовать следующий алгоритм:
ЧтениеPDF.Подписи.МенеджерКриптографии, передавая туда данные подписи как внешнюю структуру.Чтобы штампы нескольких подписантов не накладывались друг на друга, мы рекомендуем заранее продумать сетку расположения. Посмотрим на возможные варианты решения:
Лево и Низ.ОписаниеПодписиPDF к их координатам.ЧтениеPDF.Подписи.Количество() и вычисляет смещение для нового штампа автоматически.Таким образом, использование объектов ОписаниеПодписиPDF и ЗаписьPDF в сочетании с асинхронными методами позволяет создавать сложные юридически значимые бизнес-процессы согласования документов в формате PDF, сохраняя визуальную наглядность и техническую валидность всех электронных подписей.