기존 서명 검사와 신뢰 경계 이해하기
한눈에 보기
섹션 제목: “한눈에 보기”이 레시피는 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는 파일에 서명 딕셔너리가 있음을 보고합니다. 이 값은 CMS 구조, 바이트 범위 다이제스트, 서명 인증서, 인증서 체인, 폐기 상태를 확인하지 않습니다. 변조된 파일도 여전히hasSigned = true로 보고될 수 있습니다. 존재 여부를 무결성이나 작성자 증명의 근거로 절대 간주하지 마십시오. - 전체 검증에 필요한 것. 완전한 판정을 내리려면 바이트 범위 다이제스트를 다시 계산해 비교하고(ISO 32000-2 §12.8.1), CMS SignedData를 검증하며, 신뢰 앵커까지의 X.509 경로를 구축해 확인하고, OCSP 또는 CRL을 통해 폐기 상태를 확인해야 합니다. 장기 입력의 경우 검증 데이터는 DSS에 저장됩니다(ETSI EN 319 142-2 §6.3.1). 이러한 작업은
SignerInterface및LtvManagerInterface계약 뒤에서 수행됩니다. 프로덕션 구현은 Pro 및 Enterprise 에디션에 포함되어 있습니다. 외부 검증기도 지원되는 다른 경로입니다. - 검사 깊이와 사이드카(SIDECAR-001). 기본
new Inspector()에는 Spectrum 사이드카가 구성되어 있지 않습니다. 사이드카가 없으면InspectDepth::Quick만 결과를 반환합니다.InspectDepth::Quick은 인프로세스 PHP 대체 경로를 사용합니다.InspectDepth::Standard와InspectDepth::Full은 모두 사이드카가 필요합니다. 사용 가능한 사이드카가 없으면INSPECT-SIDECAR-001코드와 함께InspectException을 발생시킵니다(“Spectrum sidecar is required for Standard/Full depth inspection”,retryable = true).InspectConfig생성자의 기본 깊이는Standard입니다. 따라서 단순한new InspectConfig()(또는new InspectConfig(depth: InspectDepth::Standard))는 오프라인에서 사용할 수 없습니다. 이는hasSigned를 읽기도 전에 SIDECAR-001을 발생시킵니다. 이 레시피처럼 오프라인 존재 감지에는InspectConfig::quick()를 사용하십시오. Core에서는 어떤 깊이도 암호화 서명 검증을 수행하지 않습니다. - 빈 입력. 빈 문자열은
INSPECT-INPUT-001코드와 함께InspectException을 발생시킵니다. 읽기 결과를 확인하십시오. - 다중 서명. 존재 플래그는 서명 수를 세지 않으며, 승인 서명과 문서 타임스탬프를 구분하지도 않습니다. 개수나 서명별 판정이 중요한 경우 전용 검증기를 사용하십시오.
적합성
섹션 제목: “적합성”| 진술 | 사양 | 절 | reference_id (참조 ID) |
|---|---|---|---|
서명 값은 서명 딕셔너리 Contents 항목에 저장됩니다. | ISO 32000-2 | §12.8.1 | |
검증에서는 ByteRange에 대해 다이제스트를 다시 계산하며, 서명 값은 제외합니다. | ISO 32000-2 | §12.8.1 | |
| 장기 검증 데이터는 DSS에 저장됩니다. | ETSI EN 319 142-2 | §6.3.1 |
이 레시피는 서명을 감지합니다. 어떤 서명이 유효하거나, 신뢰할 수 있거나, 폐기되지 않았다고 주장하지는 않습니다. 그 판정은 암호화 검증기가 내립니다.