Проверка наличия подписи и понимание границы доверия
Краткий обзор
Заголовок раздела «Краткий обзор»С помощью инспектора Core определите, есть ли в PDF подпись, и чётко учитывайте границу доверия. Обнаружение — ещё не проверка. Криптографическую проверку, проверку пути доверия и проверку отзыва выполняют premium-редакции или внешний верификатор.
Предварительные требования
Заголовок раздела «Предварительные требования»- Установлен Core:
composer require nextpdf/core:^3. - PDF-файл для проверки.
- Прочитайте байты PDF-файла.
- Создайте
Inspectorи вызовитеinspect(). - Проверьте
InspectResult::$hasSigned. Значениеtrueозначает, что файл содержит словарь подписи. - Проверьте
InspectResult::$isEncryptedи флаги риска, чтобы получить дополнительный контекст. - Передайте файл верификатору, чтобы получить криптографическое решение. Инспектор сообщает о наличии, а не о действительности.
На схеме ниже показана граница: наличие — это не действительность. Там же показаны проверки, которые всё равно должен выполнить настоящий верификатор.
Полный пример
Заголовок раздела «Полный пример»<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Inspect\Inspector;use NextPDF\Inspect\InspectConfig;
$pdfData = file_get_contents(__DIR__ . '/incoming.pdf');if ($pdfData === false || $pdfData === '') { fwrite(STDERR, "Cannot read incoming.pdf\n"); exit(1);}
$inspector = new Inspector();
// InspectConfig::quick() selects InspectDepth::Quick. This is the only// depth that runs offline: a default Inspector has no Spectrum sidecar,// and without a sidecar Quick is the sole path that returns a result.// Standard and Full require the sidecar (see the SIDECAR-001 edge case).$result = $inspector->inspect( $pdfData, InspectConfig::quick(),);
// hasSigned reports the PRESENCE of a signature dictionary.// It does NOT mean the signature verifies.if ($result->hasSigned) { echo "A signature is present in incoming.pdf\n"; echo "Encrypted: " . ($result->isEncrypted ? 'yes' : 'no') . "\n"; echo "Next step: run a cryptographic verifier before trusting it.\n";} else { echo "No signature found in incoming.pdf\n";}Ожидаемый вывод
Заголовок раздела «Ожидаемый вывод»Для подписанного входного файла:
A signature is present in incoming.pdfEncrypted: noNext step: run a cryptographic verifier before trusting it.Для неподписанного входного файла:
No signature found in incoming.pdfГраничные случаи
Заголовок раздела «Граничные случаи»- Наличие — это не действительность: граница.
InspectResult::$hasSignedсообщает, что в файле есть словарь подписи. Он не проверяет структуру Cryptographic Message Syntax (CMS), дайджест по диапазону байтов, сертификат подписанта, цепочку сертификатов или статус отзыва. Изменённый файл всё равно может сообщитьhasSigned = true. Никогда не считайте наличие подтверждением целостности или авторства. - Что требуется для полной проверки. Полная проверка пересчитывает дайджест по диапазону байтов и сравнивает его (ISO 32000-2 §12.8.1), проверяет CMS SignedData, строит и проверяет путь X.509 до доверенного якоря и проверяет отзыв через Online Certificate Status Protocol (OCSP) или список отозванных сертификатов (CRL). Для долгосрочных входных файлов данные проверки хранятся в Document Security Store (DSS) (ETSI EN 319 142-2 §6.3.1). Эти операции выполняются через контракты
SignerInterfaceиLtvManagerInterface; рабочие реализации поставляются в редакциях Pro и Enterprise. Внешний валидатор — ещё один поддерживаемый путь. - Глубина проверки и sidecar (SIDECAR-001). В
new Inspector()по умолчанию Spectrum sidecar не настроен. Без sidecar результат возвращает толькоInspectDepth::Quick.InspectDepth::Quickиспользует внутрипроцессный резервный механизм PHP. ДляInspectDepth::StandardиInspectDepth::Fullтребуется sidecar. Если sidecar недоступен, они выбрасываютInspectExceptionс кодомINSPECT-SIDECAR-001(“Spectrum sidecar is required for Standard/Full depth inspection”,retryable = true). Для конструктораInspectConfigглубина по умолчанию —Standard. Поэтому простойnew InspectConfig()(илиnew InspectConfig(depth: InspectDepth::Standard)) не подходит для офлайн-использования. Он выбрасывает SIDECAR-001 ещё до того, какhasSignedбудет прочитан. ИспользуйтеInspectConfig::quick()для офлайн-обнаружения наличия, как в этом рецепте. Ни одна глубина не выполняет криптографическую проверку подписи в Core. - Пустой ввод. Для пустой строки выбрасывается
InspectExceptionс кодомINSPECT-INPUT-001. Защитите чтение файла проверкой. - Несколько подписей. Флаг наличия не подсчитывает подписи и не отличает подпись утверждения от метки времени документа. Используйте специализированный верификатор, когда важны количество подписей или вердикт по каждой из них.
Соответствие
Заголовок раздела «Соответствие»| Утверждение | Спецификация | Пункт | идентификатор (reference_id) |
|---|---|---|---|
Значение подписи хранится в записи Contents словаря подписи. | ISO 32000-2 | §12.8.1 | |
Проверка пересчитывает дайджест по ByteRange, исключая значение подписи. | ISO 32000-2 | §12.8.1 | |
| Данные долгосрочной проверки хранятся в DSS. | ETSI EN 319 142-2 | §6.3.1 |
Этот рецепт позволяет определить, есть ли подпись. Он не утверждает, что какая-либо подпись действительна, доверена или не отозвана. Это решение принимает криптографический верификатор.