مقال تقني

تصنيف ما تغير في PDF بعد توقيعه

التوقيع على PDF لا يحظر التعديلات اللاحقة. فهو يثبت مدى بايتات، والتحديث التزايدي يضيف بايتات جديدة بعده، فيبقى التوقيع صالحا رياضيا بينما يكتسب المستند محتوى جديدا. أما كون ذلك المحتوى مقبولا فمسألة سياسة، وDocMDP هو الموضع الذي يصرح فيه المؤلف بالسياسة: لا تعديل على الإطلاق، أو تعبئة النماذج والتوقيع فقط، أو ذلك مع التعليقات التوضيحية. وفرضها يعني تصنيف ما تغير فعلا، وهو ما يفعله AnalyzeModifications. وجّهه إلى مراجعة سابقة، ثم اقرأ GetModificationLevel للحكم الكلي، ودوال الوصول لكل نتيجة لمعرفة المستوى ورقم الكائن ووصف كل فرق

وبتوفر ذلك، ينكمش فرض DocMDP إلى مقارنة: هل المستوى المحسوب عند مستوى السياسة المسموح أو دونه

مخطط سلم مستويات التعديل في PDFlibPas من mlNone إلى mlUnclassified يظهر فرض سياسة DocMDP كمقارنة واحدة في Delphi
سلم TPLModificationLevel يمتد من mlNone إلى mlUnclassified، وينحصر فرض DocMDP في مقارنة المستوى المحسوب بالسياسة

لماذا يُتوقع أن يتغير PDF موقّع

ثلاث حالات مشروعة تغطي معظم ما ستراه. موقّع ثانٍ يضيف توقيعه. ومستلم يملأ حقول نموذج تركها المؤلف مفتوحة. ومواد التحقق طويل الأمد تُلحق: استجابات OCSP وقوائم CRL تكتب في مخزن أمان المستند كي يظل التوقيع قابلا للتحقق بعد اختفاء المستجيبين. وهذه الأخيرة ليست مسموحا فحسب، بل هي ما يفعله الأرشيف حسن الإدارة عمدا للمستندات الموقعة

فعبارة «كبر الملف بعد التوقيع» لا تحمل أي معلومة. السؤال دائما هو ما أضيف، والجواب لا بد أن يأتي من مقارنة حالات المستند لا من مراقبة البايتات. وآليات الإلحاق ذاتها مشمولة في مقال التحديث التزايدي

صنّف بحسب هيئة الكائن، لا بحسب المسار الذي أنتجه

ينظر المصنف إلى ما هو عليه الكائن بعد التغيير، لا إلى نداء المكتبة الذي أنشأه. وهذا مقصود، لأن التحليل يعمل على ملفات أنتجتها برمجيات أخرى لا يتوفر فيها مسار نداء لفحصه

تُعرف أربع هيئات. قواميس مخزن أمان المستند والمعلومات المتعلقة بالتحقق، وكائنات مسار المراجع المتقاطع، ومدخلة البيانات الوصفية للفهرس، وقواميس التوقيع الحاملة لمدى بايتات، كلها مواد أرشفة طويلة الأمد. والكائن الحامل معا لنوع حقل وقيمة حقل هو تعبئة نماذج. والكائن الذي نوعه تعليق توضيحي، أو الذي نوعه الفرعي أحد المذكورين في الجدول 168 من ISO 32000-2، هو تعديل تعليق توضيحي. وكل ما عداه غير مصنف

شجرة قرار يطبقها PDFlibPas على كل كائن PDF متغير، مصنفا التعديلات في مستويات أرشيف أو تعبئة نماذج أو تعليق توضيحي أو غير مصنف
كل كائن متغير يصنف بحسب ما هو — مخزن أمان أو مسار مراجع أو حقل أو تعليق توضيحي — لا بحسب النداء الذي أنتجه

الإزالات تعامل بصرامة أكبر من الإضافات. الكائن المزال يدخل قائمة السماح فقط عندما يكون الكائن على الجانب القديم هو ذاته مادة أرشيف، وهو ما يغطي الحالة الاعتيادية لاستبدال مخزن أمان بآخر أحدث. وكل إزالة أخرى غير مصنفة، لأن حذف محتوى من مستند موقع ليس شيئا يأذن به مستوى صلاحية. واختلافات مستوى المستند أكثر صرامة: تغير عدد الصفحات يذهب مباشرة إلى غير مصنف دون فحص كائنات فردية، لأنه لا يوجد مستوى DocMDP يسمح بإضافة صفحات أو إزالتها

قائمة السماح تخطئ في اتجاه الرفض

هذه هي قاعدة التصميم التي تحكم كل قرار على الحد الفاصل. فالتغيير المصنف خطأ كمسموح به توقيع يصحح فوق محتوى لم يؤذن به المؤلف أبدا. والتغيير المصنف خطأ كغير مصنف مستند يُعلَّم ويراجعه إنسان. هذان الخطآن غير متناظرين، فتبقى قائمة السماح ضيقة وتسقط الهيئات غير المعروفة إلى غير مصنف بدل التخمين بشأنها

لهذا أثر عملي يستحق التوقع: الملفات من منتجين غير مألوفين ستسجل أحيانا تعديلات غير مصنفة تكون عند الفحص حميدة. والاستجابة الصحيحة هي النظر إلى تفصيل النتيجة ورقم الكائن لا توسيع قائمة السماح، لأن قائمة سماح تنمو لكتم تقارير فردية تتوقف عن كونها ضابطة أمن

uses
  PDFlibrary, PDFlibCompare;

var
  Pdf: TPDFlib;
  I, Level: Integer;
begin
  Pdf := TPDFlib.Create(nil);
  try
    Pdf.LoadFromFile('contract-countersigned.pdf', '');
    if Pdf.AnalyzeModifications('contract-as-signed.pdf', '') < 0 then
      raise Exception.Create('the earlier revision could not be loaded');

    // TPLModificationLevel مرتبة: mlNone وmlLTAUpdates وmlFormFilling
    // وmlAnnotations وmlUnclassified؛ والتابع الجالب يعيد رتبتها الترتيبية
    Level := Pdf.GetModificationLevel;
    // فرض DocMDP صار الآن مقارنة واحدة مقابل السياسة
    if Level > Ord(mlFormFilling) then
      for I := 0 to Pdf.GetModificationFindingCount - 1 do
        Report.Add(Format('object %d, level %d: %s',
          [Pdf.GetModificationFindingObjNum(I),
           Pdf.GetModificationFindingLevel(I),
           Pdf.GetModificationFindingDetail(I)]));
  finally
    Pdf.Free;
  end;
end;

المستوى الكلي هو الأعظم عبر كل النتائج، وهو التجميع الوحيد القابل للدفاع عنه: مستند يضم تسعة وتسعين إضافة أرشيفية وتعديلا واحدا غير مصنف هو مستند بتعديل غير مصنف

في الأسفل: بصمات لا دالات تجزئة تشفيرية

محرك المقارنة الذي تكشفه CompareWith والذي بُني عليه تحليل التعديلات، يحدد الكائنات ببصمة لجسمها المطبّع باستخدام دالة تجزئة ذات 64 بت غير تشفيرية بدلا من SHA-256. وهذا خيار مدروس. ما تحتاجه المقارنة البنيوية هو الحتمية: يجب أن ينتج جسم الكائن نفسه البصمة نفسها دائما ضمن تشغيلة واحدة. وهو لا يحتاج مقاومة التصادم، لأن مهاجما يتحكم في طرفي المقارنة قد فاز أصلا بوسائل أخرى، ودفع كلفة دالة تجزئة تشفيرية كاملة على كل كائن في مستند بمليون كائن كلفة حقيقية بلا منفعة

قاعدتا تطبيع أهمان من اختيار دالة التجزئة. المراجع غير المباشرة تنطوي إلى رمز نائب بدل توسيعها إلى المحتوى المشار إليه: فالتوسيع سينسخ جسم كائن مشترك إلى كل مُحيل، فيبطل تعديل صغير واحد لموصّف خط مشترك بصمة كل كائن يصل إليه، ويصبح التقرير غير مقروء. وأرقام الكائنات ذاتها مستثناة من البصمة، لأن إعادة الكتابة يمكن أن تعيد ترقيم الكائنات دون تغيير أي شيء دلالي

ثم تجري المطابقة في مرورين: مواءمة بالبصمة أولا، ثم إقران الباقي برقم الكائن لتحديد التغييرات بدل إضافة تليها إزالة. والفحوص الرخيصة أولا في كل مكان: فرق عدد الصفحات يبلّغ عنه قبل بدء أي اجتياز للكائنات

فرق مراجعات PDF بمرورين في PDFlibPas: فحص عدد الصفحات أولا، وبصمات 64 بت، ثم مواءمة بالبصمة فإقران برقم الكائن
محرك المقارنة يبصم أجسام الكائنات المطبّعة ويبلّغ عن فروق عدد الصفحات أولا ثم يطابق بالبصمة ورقم الكائن

فخ: المقارنة الذاتية ليست مضمونة التطابق

الاختبار الأول الطبيعي لمحرك فروق هو مقارنة ملف بنفسه والتوكيد على أن النتيجة متطابقة. وهذا التوكيد لا يصح هنا، والسبب موعظة مفيدة. فمسار التحميل العام ومسار تحميل المستند الأدنى مستوى لا يضبطان فك الترميز بالطريقة نفسها، فيمكن للملف ذاته المحمل عبر الطريقين أن ينتج بصمات مختلفة لبعض الكائنات. المحرك ليس خاطئا؛ التحميلان أنتجا فعلا حالتين مختلفتين في الذاكرة

بدل إجبار المسارين على الاتحاد، نصت دلالات المقارنة على نحو ضيق: التحليل يقارن حالة المستند الحالية بمراجعة سابقة، ويفيد بالتطابق فقط عندما تتطابق مجموعتا البصمات تماما. هذا هو السؤال الذي يطرحه المستخدمون فعلا، ولا يتطلب أن يكون المحملان قابلين للتبادل. وعند تصميم ميزة مقارنة، تحديد معنى «متماثل» جزء من العمل أكبر من حسابه

أين تستخدمه

موضعان. في تقرير تحقق، بجانب فحص التوقيع، ليرى المراجع لا فقط هل التوقيع سليم تشفيريا بل ما حدث للمستند بعد ذلك؛ وجهة التوقيع مشمولة في توقيع PAdES والتحقق منه. وفي بوابة استلام، حيث يفحص مستند قادم من الخارج مقابل النسخة التي أرسلتها، فيعامل عقد مرتجع أضيفت إليه تعليقة توضيحية معاملة مختلفة عن عقد عدلت صفحته

تحذير واحد عن النطاق. هذا التحليل يخبرك بما تغير بين مراجعتين من النسالة نفسها للمستند. وهو لا يخبرك هل المحتوى المرئي مضلل، وهل مسار مظهر حقل نموذج يطابق قيمته، وهل النص المخفي تحت طبقة عازلة ما يزال موجودا في مسار المحتوى. تلك تحتاج معالجة منفصلة، وجانب إزالة المحتوى منها مشمول في مقال الحجب الحقيقي. ونقاط دخول التحليل والمقارنة موثقة في صفحة منتج losLab PDF Developer Library