Bỏ qua để đến nội dung

Kiểm tra chữ ký hiện có và hiểu ranh giới tin cậy

Dùng trình kiểm tra Core để phát hiện một PDF có chứa từ điển chữ ký hay không. Trình kiểm tra chạy ngoại tuyến và không dùng sidecar Spectrum. Công thức này cũng làm rõ ranh giới tin cậy: phát hiện chữ ký không đồng nghĩa với xác minh chữ ký đó. Xác minh mật mã, kiểm định đường dẫn tin cậy và kiểm tra thu hồi thuộc phạm vi Premium hoặc một trình xác minh bên ngoài.

Terminal window
composer require nextpdf/core:^3

Chữ ký PDF là một trường chữ ký có giá trị là một từ điển chữ ký (ISO 32000-2 §12.7.4). Mục Contents của từ điển chứa Cryptographic Message Syntax (CMS) SignedData được mã hóa DER (ISO 32000-2 §12.8.1). Phương án dự phòng Quick của Inspector phát hiện sự hiện diện của cấu trúc đó bằng cách quét các dấu hiệu chữ ký. Nó không phân tích cú pháp CMS, không tính lại bản tóm tắt theo dải byte (vốn loại trừ giá trị chữ ký — ISO 32000-2 §12.8.1), không kiểm định chuỗi chứng chỉ, và không kiểm tra thu hồi.

Gọi new Inspector(), rồi ->inspect(string $pdfData, InspectConfig $config). Dùng InspectConfig::quick() để chạy phương án dự phòng PHP ngoại tuyến. InspectDepth::Standard/Full yêu cầu sidecar Spectrum và sẽ fail closed (INSPECT-SIDECAR-001) khi không có sidecar. Kết quả trả về là một value object InspectResult. Trong quy trình này, dùng $hasSigned cho sự hiện diện của chữ ký, cùng với $isEncrypted$pdfVersion.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Inspect\InspectConfig;
use NextPDF\Inspect\Inspector;
$pdfData = file_get_contents(__DIR__ . '/incoming.pdf');
if ($pdfData === false || $pdfData === '') {
fwrite(STDERR, "Cannot read incoming.pdf\n");
exit(1);
}
$result = (new Inspector())->inspect($pdfData, InspectConfig::quick());
// hasSigned reports the PRESENCE of a signature dictionary.
// It does NOT mean the signature verifies.
echo $result->hasSigned
? "A signature is present — NOT verified.\n"
: "No signature found.\n";

Chương trình độc lập này chạy trong bộ khung kiểm thử của cookbook. Nó tương ứng với examples/37-inspect-existing-signature.php. Nó kiểm tra một mẫu trong corpus đã biết là có chữ ký và một tài liệu chưa ký được tạo mới, để bạn quan sát được cả hai nhánh của cờ hiện diện. Sau đó, nó không diễn giải kết luận xa hơn. Sự hiện diện là dữ liệu đầu vào để định tuyến, không bao giờ là một kết luận về tin cậy. Tệp được chuyển cho một trình xác minh mật mã (Pro hoặc bên ngoài). Ở đây, tệp không được tin cậy.

<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\Document;
use NextPDF\Inspect\InspectConfig;
use NextPDF\Inspect\Inspector;
$inspector = new Inspector();
// --- A known-signed input ---
// The repository corpus carries synthetic PAdES samples. In your
// application this is simply the incoming PDF you received.
$signedPath = __DIR__ . '/tests/Corpus/pades/pades-b-b-bytepattern-synthetic.pdf';
if (is_file($signedPath)) {
$signed = (string) file_get_contents($signedPath);
$r = $inspector->inspect($signed, InspectConfig::quick());
echo "Signed sample:\n";
echo ' Signature present : ' . ($r->hasSigned ? 'yes' : 'no') . "\n";
echo ' Encrypted : ' . ($r->isEncrypted ? 'yes' : 'no') . "\n";
echo ' PDF version : ' . ($r->pdfVersion ?? 'unknown') . "\n";
echo " Verdict : presence detected — NOT verified.\n";
if ($r->hasSigned) {
// Presence detected. This is routing input, not a trust verdict.
// Hand the file to a cryptographic verifier (Pro or external)
// before relying on it. (Pseudo-queue shown; wire your own.)
// $verifierQueue->enqueue($signed);
echo " Next step : run a cryptographic verifier before trusting it.\n";
}
} else {
echo "Signed corpus sample absent; skipping the signed branch.\n";
}
// --- A known-unsigned input ---
$unsigned = Document::createStandalone();
$unsigned->setTitle('Unsigned sample');
$unsigned->addPage();
$unsigned->setFont('helvetica', '', 12);
$unsigned->cell(0, 10, 'This document carries no signature.', newLine: true);
$unsignedBytes = $unsigned->getPdfData();
$ru = $inspector->inspect($unsignedBytes, InspectConfig::quick());
echo "Unsigned sample:\n";
echo ' Signature present : ' . ($ru->hasSigned ? 'yes' : 'no') . "\n";
// The harness sets NEXTPDF_COOKBOOK_OUTPUT and runs this script under the
// semantic profile; emit the unsigned document to the side-channel.
$out = getenv('NEXTPDF_COOKBOOK_OUTPUT');
file_put_contents($out !== false && $out !== '' ? $out : __DIR__ . '/inspected.pdf', $unsignedBytes);

STDOUT dự kiến (nhánh có chữ ký sẽ bị bỏ qua nếu thiếu mẫu corpus):

Signed sample:
Signature present : yes
Encrypted : no
PDF version : <version>
Verdict : presence detected — NOT verified.
Next step : run a cryptographic verifier before trusting it.
Unsigned sample:
Signature present : no

Trường hợp đặc biệt & điểm cần lưu ý

Phần tiêu đề “Trường hợp đặc biệt & điểm cần lưu ý”
  • Hiện diện không phải là hợp lệ. $hasSigned báo cáo rằng có tồn tại một từ điển chữ ký. Nó không kiểm tra cấu trúc CMS, bản tóm tắt theo dải byte, chứng chỉ ký, chuỗi chứng chỉ, hay việc thu hồi. Tệp đã bị giả mạo vẫn có thể báo cáo hasSigned = true. Đừng bao giờ xem sự hiện diện là bằng chứng về tính toàn vẹn hay quyền tác giả.
  • Xác minh đầy đủ cần những gì. Một quyết định hoàn chỉnh sẽ tính lại bản tóm tắt theo dải byte (ISO 32000-2 §12.8.1), kiểm định CMS SignedData, dựng và kiểm tra đường dẫn X.509 đến một anchor đáng tin cậy, và kiểm tra việc thu hồi thông qua Online Certificate Status Protocol (OCSP) hoặc một certificate revocation list (CRL). Dấu thời gian chữ ký, khi có, được xác minh riêng dựa trên dấu in của nó trên các octet giá trị chữ ký (ETSI EN 319 122-1 §5.3). Các thao tác này nằm phía sau các signing contract. Các bản triển khai cho môi trường thật được cung cấp trong Pro và Enterprise. Hướng còn lại được hỗ trợ là dùng một trình kiểm định bên ngoài.
  • Độ sâu kiểm tra. InspectConfig::quick() là độ sâu duy nhất chạy được mà không cần sidecar Spectrum. Standard/Full ném INSPECT-SIDECAR-001 khi không có sidecar.
  • Đầu vào rỗng. Một chuỗi rỗng sẽ ném một inspect exception với nội dung “PDF data must not be empty”. Hãy bảo vệ thao tác đọc.
  • Nhiều chữ ký / dấu thời gian. Cờ hiện diện không đếm số chữ ký và không phân biệt một chữ ký phê duyệt với một dấu thời gian tài liệu (vốn cũng được mang trong unsignedAttrs theo RFC 5652 §5.3). Hãy dùng một trình xác minh chuyên dụng khi số lượng hoặc kết luận cho từng chữ ký có ý nghĩa quan trọng.

Phương án dự phòng Quick thực hiện một lượt quét có giới hạn qua các byte của tài liệu. Nó không phân tích cú pháp toàn bộ đồ thị đối tượng. Hãy dùng nó để phân loại nhanh các tệp đến trước khi bạn định tuyến chúng đến một trình xác minh nặng hơn.

Trình kiểm tra là một công cụ phân loại, không phải một ranh giới tin cậy. Một kết quả hasSigned dương tính không bao giờ tự nó đủ để đưa ra quyết định tin cậy.

Nơi lưu trú dữ liệu & biện pháp giảm thiểu PII

Phần tiêu đề “Nơi lưu trú dữ liệu & biện pháp giảm thiểu PII”

Việc kiểm tra chạy hoàn toàn trong tiến trình. Không có byte nào của tài liệu rời khỏi máy chủ. Phương án dự phòng Quick chỉ đọc các dấu hiệu cấu trúc, không đọc phần văn bản của tài liệu, nên nó không trích xuất hay truyền đi thông tin nhận dạng cá nhân (PII).

Inspector chấp nhận một logger PSR-3 tùy chọn. Nó ghi nhật ký nhánh đã chọn (“Spectrum unavailable, using PHP fallback”), không ghi nội dung tài liệu. Đừng ghi nhật ký nguyên văn các byte PDF được kiểm tra hoặc InspectResult nếu tài liệu nhạy cảm.

Đã xét đến: một tệp bị giả mạo nhưng đưa ra một từ điển chữ ký hợp lệ về mặt cú pháp (trình kiểm tra báo cáo sự hiện diện; nó nói rõ là không khẳng định tính toàn vẹn), và một tệp không có chữ ký (được báo cáo chính xác là không có). Không khẳng định: bất kỳ chữ ký nào được phát hiện là hợp lệ về mặt mật mã, đáng tin cậy, hay chưa bị thu hồi — đó là việc của trình xác minh.

Phương án dự phòng Quick không thực hiện thao tác mật mã nào, nên chế độ Federal Information Processing Standards (FIPS) không liên quan đến công thức này. Xác minh mật mã (Premium/bên ngoài) là nơi mà chuỗi nhà cung cấp FIPS có ý nghĩa.

Phát biểuĐặc tảĐiều khoảnreference_id
Giá trị của một trường chữ ký là một từ điển chữ ký.ISO 32000-2§12.7.4
Contents chứa CMS SignedData dạng DER; một Contents của dấu thời gian tài liệu chứa một TimeStampToken.ISO 32000-2§12.8.1
Việc xác minh tính lại bản tóm tắt trên dải byte, loại trừ giá trị chữ ký.ISO 32000-2§12.8.1
Dấu in của dấu thời gian chữ ký bao trùm các octet giá trị chữ ký của SignerInfo.ETSI EN 319 122-1§5.3
Một dấu thời gian được mang trong unsignedAttrs của SignerInfo.RFC 5652§5.3

Công thức này phát hiện chữ ký. Nó không khẳng định rằng bất kỳ chữ ký nào là hợp lệ, đáng tin cậy, hay chưa bị thu hồi. Trình xác minh mật mã mới là nơi đưa ra quyết định đó.

Việc xác minh CMS bằng mật mã, kiểm định đường dẫn X.509, và kiểm tra thu hồi qua OCSP/CRL được cung cấp phía sau các signing contract trong các phiên bản Pro và Enterprise. Trình kiểm tra Core chỉ bao gồm khả năng phát hiện sự hiện diện.