Как добавить подписи безопасности PDF в Python

Как добавить подписи безопасности PDF в Python

Aspose.PDF FOSS для Python включает детектор компрометации подписи, который проверяет уже подписанный PDF на наличие специфического шаблона подделки: значимые байты, добавленные после диапазона подписанных байтов подписи, риск, характерный для инкрементно-обновляемых PDF-файлов. Это руководство добавляет эту проверку в рабочий процесс Python с использованием классов SignaturesCompromiseDetector и CompromiseCheckResult. Создание или применение новых цифровых подписей является отдельной частью библиотеки и здесь не рассматривается. Библиотека устанавливается командой ниже.

Пошаговое руководство

Шаг 1: Установить пакет

Установите пакет Aspose.PDF FOSS:

git clone https://github.com/aspose-pdf-foss/Aspose-PDF-FOSS-for-Python.git
cd Aspose-PDF-FOSS-for-Python
pip install -e .

Проверьте установку, импортировав SignaturesCompromiseDetector и выведя сообщение подтверждения:

from aspose_pdf import SignaturesCompromiseDetector
print("aspose-pdf-foss-for-python is ready.")

Шаг 2: Импортировать необходимые классы

from aspose_pdf import CompromiseCheckResult, SignaturesCompromiseDetector

Шаг 3: Подготовить объект, предоставляющий список подписей

SignaturesCompromiseDetector не разбирает PDF сам по себе — его конструктор принимает любой объект, который предоставляет атрибут signatures: список записей подписей, каждая из которых содержит valid, byte_range и reference_data. PdfSignature — простой, непосредственно создаваемый класс — соответствует этой структуре, поэтому его удобно использовать для наблюдения за поведением проверки перед подключением к вашему собственному объекту документа:

from types import SimpleNamespace
from aspose_pdf import PdfSignature

with open("signed.pdf", "rb") as handle:
    pdf_bytes = handle.read()

signature = PdfSignature(
    name="Signature1",
    contents=b"...",  # PKCS#7 signed-data blob from the signature dictionary
    byte_range=[0, 1024, 1040, len(pdf_bytes) - 1040],
    reference_data=pdf_bytes,
)

signed_document = SimpleNamespace(signatures=[signature])

Замените signed_document на ваш собственный объект документа, как только он будет предоставлять список signatures в той же форме — любой объект с этим атрибутом подойдет.


Шаг 4: Выполнить проверку на компромисс

from aspose_pdf import SignaturesCompromiseDetector

detector = SignaturesCompromiseDetector(signed_document)
result = detector.check()

print(result.compromised)                # bool
print(result.has_compromised_signatures)  # bool -- same value as compromised
print(result.signatures_coverage)         # int -- number of signatures inspected
print(result.reasons)                     # list[str] -- human-readable findings

check() проходит по каждой подписи в signed_document.signatures, ищет неподписанный контент, добавленный после диапазона подписанных байтов каждой подписи. CompromiseCheckResult подводит итог результата: compromised и has_compromised_signatures сообщают один и тот же логический результат под разными названиями, signatures_coverage сообщает, сколько подписей было проверено, а reasons перечисляет человекочитаемое объяснение каждой найденной проблемы.


Шаг 5: Обработать документ без подписей

Пустой или отсутствующий список signatures не является ошибкой — он сообщается так же, как документ, в котором нет ничего для проверки:

from types import SimpleNamespace
from aspose_pdf import SignaturesCompromiseDetector

unsigned_document = SimpleNamespace(signatures=[])
detector = SignaturesCompromiseDetector(unsigned_document)
result = detector.check()

print(result.compromised)  # False
print(result.reasons)      # ["unsigned document"]

Передача SignaturesCompromiseDetector(None) — значение по умолчанию конструктора — ведёт себя так же.

Распространённые проблемы и их решения

compromised is False для PDF, который, как вы знаете, был отредактирован после подписи

SignaturesCompromiseDetector ищет конкретно неподписанные байты, добавленные после диапазона подписанных байтов подписи — шаблон, характерный для наивного подделывания посредством инкрементального обновления. Он не выполняет полную криптографическую проверку подписи. Для этого вызовите validate() для отдельного объекта PdfSignature.

compromised and has_compromised_signatures кажется избыточным

Это одно и то же значение: compromised — вычисляемое свойство, которое возвращает has_compromised_signatures. Используйте то имя, которое лучше читается в вашем коде.

Исключение не возникает, когда у документа нет signatures атрибута вовсе

SignaturesCompromiseDetector рассматривает документ без signatures атрибута, или document=None, так же, как неподписанный документ — check() возвращает результат с has_compromised_signatures=False и reasons=["unsigned document"], а не генерирует ошибку.

Некорректный PdfSignature не помечается

check() пропускает любую подпись, у которой byte_range не является 4-элементным списком, или у которой reference_data не равен bytes/bytearray, вместо того чтобы генерировать ошибку или сообщать о компрометации. Подпись, построенная с неверной структурой, молча исключается из проверки, не помечается.

Смешивание этого детектора с созданием подписи

SignaturesCompromiseDetector и CompromiseCheckResult только проверяют подписи, уже существующие в документе — они не умеют создавать, применять или встраивать новую подпись.

Часто задаваемые вопросы

Что именно считается «компрометированным» в данном случае?

Содержательные, не пробельные байты, добавленные в PDF после диапазона подписанных байтов подписи — с двумя исключениями, которые детектор уже учитывает: более поздняя подпись или метка времени, которые сами охватывают эти байты, и инкрементальное обновление, которое только добавляет проверочный материал (например, /DSS), не накладывая новый контент, такой как аннотации.

Проверяет ли это криптографическую валидность самой подписи?

Нет. SignaturesCompromiseDetector проверяет наличие признаков подделки вокруг диапазона подписанных байтов. Криптографическая валидность — отдельная проверка, доступная через PdfSignature.validate().

Что мне сообщает signatures_coverage?

Количество подписей, которые проверка фактически проанализировала в переданном документе, — полезно для подтверждения того, что детектор увидел ожидаемые вами подписи, прежде чем доверять чистому результату.

Могу ли я проверить документ с несколькими подписями одновременно?

Да. check() перебирает каждую запись в signed_document.signatures и возвращает один агрегированный CompromiseCheckResult, охватывающий все их.

Нужно ли мне самостоятельно создавать объекты PdfSignature в обычном использовании?

Нет — создание PdfSignature на Шаге 3 предназначено для прямого исследования поведения детектора. В реальном рабочем процессе передайте любой объект, который уже генерирует ваш код загрузки документа, при условии, что он предоставляет список signatures из записей формы PdfSignature.

См. также:

 Русский