افحص توقيعًا موجودًا وافهم حدود الثقة
لمحة سريعة
قسم بعنوان «لمحة سريعة»استخدم أداة الفحص في Core للكشف عمّا إذا كان ملف PDF يتضمّن قاموس توقيع. تعمل أداة الفحص دون اتصال ولا تستخدم وحدة Spectrum الجانبية. توضّح هذه الوصفة أيضًا حدود الثقة: فالكشف عن التوقيع لا يعني التحقق منه. أمّا التحقق التشفيري، والتحقق من مسار الثقة، وفحص الإبطال فهي ميزات في الإصدار Premium أو أدوات خارجية.
التثبيت
قسم بعنوان «التثبيت»composer require nextpdf/core:^3نظرة مفاهيمية عامة
قسم بعنوان «نظرة مفاهيمية عامة»توقيع PDF هو حقل توقيع تكون قيمته قاموس توقيع (ISO 32000-2 §12.7.4). يحمل المُدخَل Contents في القاموس بنية SignedData الخاصة بصيغة رسائل التشفير (CMS) والمُرمَّزة بترميز DER (ISO 32000-2 §12.8.1). يكتشف المسار الاحتياطي السريع في Inspector وجود تلك البنية عبر مسح علامات التوقيع. وهو لا يحلّل CMS، ولا يعيد حساب موجز نطاق البايتات (الذي يستبعد قيمة التوقيع — ISO 32000-2 §12.8.1)، ولا يتحقق من سلسلة الشهادات، ولا يفحص الإبطال.
واجهة الـ API
قسم بعنوان «واجهة الـ API»استدعِ new Inspector()، ثم ->inspect(string $pdfData, InspectConfig $config). استخدم InspectConfig::quick() لتشغيل المسار الاحتياطي في PHP دون اتصال. يتطلّب InspectDepth::Standard/Full وحدة Spectrum الجانبية، ويفشل بأمان (INSPECT-SIDECAR-001) عند غيابها. تكون النتيجة كائن قيمة من النوع InspectResult. في سير العمل هذا، استخدم $hasSigned للكشف عن وجود التوقيع، إلى جانب $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";نموذج التعليمات البرمجية — الإنتاج
قسم بعنوان «نموذج التعليمات البرمجية — الإنتاج»يعمل هذا البرنامج المكتفي ذاتيًا ضمن منصّة اختبار كتاب الوصفات. وهو يحاكي examples/37-inspect-existing-signature.php. يفحص البرنامج عيّنة موقَّعة معروفة من مجموعة المستندات ومستندًا غير موقَّع أُنشئ حديثًا، حتى ترى مساري راية الوجود معًا. ثم يوجّه الحُكم إلى الخطوة التالية. الوجود مُدخَل توجيهي، وليس حُكم ثقة إطلاقًا. سلّم الملف إلى أداة تحقق تشفيري (Pro أو خارجية). ولا تثق به هنا.
<?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 المتوقَّع (يُتخطّى المسار الموقَّع إذا كانت عيّنة مجموعة المستندات غير موجودة):
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الحالات الحدّية والمزالق
قسم بعنوان «الحالات الحدّية والمزالق»- الوجود ليس صلاحية. يُبلّغ
$hasSignedعن وجود قاموس توقيع. وهو لا يفحص بنية CMS، ولا موجز نطاق البايتات، ولا شهادة التوقيع، ولا السلسلة، ولا الإبطال. قد يظل ملف مُتلاعَب به يُبلّغ بالقيمةhasSigned = true. لا تعامل الوجود مطلقًا على أنه إثبات للسلامة أو لهوية المُؤلِّف. - ما يتطلّبه التحقق الكامل. يعيد القرار الكامل حساب موجز نطاق البايتات (ISO 32000-2 §12.8.1)، ويتحقق من CMS SignedData، ويبني مسار X.509 إلى مرساة موثوقة ويتحقق منه، ويفحص الإبطال عبر بروتوكول حالة الشهادة عبر الإنترنت (OCSP) أو قائمة إبطال الشهادات (CRL). أمّا الطابع الزمني للتوقيع، عند وجوده، فيُتحقق منه بدوره مقابل بصمته الخاصة على ثُمانيّات قيمة التوقيع (ETSI EN 319 122-1 §5.3). تعمل هذه العمليات خلف عقود التوقيع. تُشحن تطبيقات الإنتاج في Pro وEnterprise. وتظل أداة التحقق الخارجية هي المسار المدعوم الآخر.
- عمق الفحص.
InspectConfig::quick()هو العمق الوحيد الذي يعمل دون وحدة Spectrum الجانبية. يطرحStandard/FullالخطأINSPECT-SIDECAR-001عندما لا تكون الوحدة الجانبية متاحة. - مُدخَل فارغ. تطرح السلسلة الفارغة استثناء فحص يحمل النص “PDF data must not be empty”. احمِ عملية القراءة بتحقق مسبق.
- التوقيعات أو الطوابع الزمنية المتعددة. لا تَعُدّ راية الوجود التوقيعات ولا تميّز توقيع الموافقة عن طابع زمني للمستند (الذي يُحمَل أيضًا في
unsignedAttrsوفق RFC 5652 §5.3). استخدم أداة تحقق مخصّصة عندما يكون العدد أو الحُكم لكل توقيع مهمًا.
الأداء
قسم بعنوان «الأداء»يُجري المسار الاحتياطي السريع مسحًا محدودًا على بايتات المستند. وهو لا يحلّل مخطط الكائنات الكامل. استخدمه لفرز الملفات الواردة بسرعة قبل توجيهها إلى أداة تحقق أكثر ثقلًا.
ملاحظات أمنية
قسم بعنوان «ملاحظات أمنية»أداة الفحص أداة فرز، وليست حدًا للثقة. يجب ألّا تتحكّم قيمة hasSigned الموجبة مطلقًا في قرار ثقة بمفردها.
موقع البيانات وإجراءات الحدّ من المعلومات الشخصية
قسم بعنوان «موقع البيانات وإجراءات الحدّ من المعلومات الشخصية»يجري الفحص بالكامل داخل العملية. لا تغادر أي بايتات من المستند المضيف. يقرأ المسار الاحتياطي السريع العلامات البنيوية فقط، لا نص المستند؛ لذلك لا يستخرج المعلومات الشخصية القابلة للتعريف (PII) ولا ينقلها.
القياس عن بُعد الآمن وتنقية السجلات
قسم بعنوان «القياس عن بُعد الآمن وتنقية السجلات»يقبل Inspector أداة تسجيل اختيارية متوافقة مع PSR-3. وهو يسجّل المسار المختار (“Spectrum unavailable, using PHP fallback”)، لا محتوى المستند. لا تسجّل بايتات ملف PDF المفحوص أو InspectResult حرفيًا إذا كان المستند حسّاسًا.
نموذج التهديد
قسم بعنوان «نموذج التهديد»المأخوذ في الحسبان: ملف مُتلاعَب به يقدّم قاموس توقيع صحيحًا نحويًا (تُبلّغ أداة الفحص عن الوجود؛ وهي لا تؤكّد السلامة صراحةً)، وملف بلا توقيع (يُبلَّغ عن غيابه بصورة صحيحة). غير المؤكَّد: أن أي توقيع مكتشَف صحيح تشفيريًا أو موثوق أو غير مُبطَل — فذلك من مهام أداة التحقق.
السلوك في وضع FIPS
قسم بعنوان «السلوك في وضع FIPS»لا يُجري المسار الاحتياطي السريع أي عمليات تشفير، لذلك لا يكون وضع معايير المعالجة الفيدرالية للمعلومات (FIPS) ذا صلة بهذه الوصفة. أمّا التحقق التشفيري (Premium/خارجي) فهو الموضع الذي تهمّ فيه سلسلة مزوّدي FIPS.
المطابقة
قسم بعنوان «المطابقة»| العبارة | المواصفة | البند | reference_id |
|---|---|---|---|
| قيمة حقل التوقيع هي قاموس توقيع. | ISO 32000-2 | §12.7.4 | |
يحمل Contents بنية CMS SignedData بترميز DER؛ ويحمل Contents الخاص بطابع زمني للمستند رمز TimeStampToken. | ISO 32000-2 | §12.8.1 | |
| يعيد التحقق حساب الموجز على نطاق البايتات، مع استبعاد قيمة التوقيع. | ISO 32000-2 | §12.8.1 | |
| تكون بصمة الطابع الزمني للتوقيع على ثُمانيّات قيمة التوقيع في SignerInfo. | ETSI EN 319 122-1 | §5.3 | |
| يُحمَل الطابع الزمني في unsignedAttrs الخاص بـSignerInfo. | RFC 5652 | §5.3 |
تكتشف هذه الوصفة وجود توقيع. وهي لا تؤكّد أن أي توقيع صالح أو موثوق أو غير مُبطَل. أداة التحقق التشفيري هي التي تتخذ هذا القرار.
السياق التجاري
قسم بعنوان «السياق التجاري»يُشحن التحقق التشفيري من CMS، والتحقق من مسار X.509، وفحص الإبطال عبر OCSP/CRL خلف عقود التوقيع في إصداري Pro وEnterprise. ولا تغطّي أداة الفحص في Core سوى الكشف عن الوجود.