امضای روی یک PDF تغییرات بعدی را ممنوع نمیکند. یک بازه بایتی را قفل میکند، و یک بهروزرسانی افزایشی بایتهای جدیدی را پس از آن میچسباند، پس امضا از نظر ریاضی معتبر میماند در حالی که سند محتوای جدیدی میگیرد. اینکه آن محتوا قابل قبول است یا نه یک پرسش خطمشی است، و DocMDP جایی است که مؤلف خطمشی را اعلام میکند: هیچ تغییری مگر نه، فقط پرکردن فرم و امضا، یا آنها بهعلاوه حاشیهنویسی. اجرای آن یعنی طبقهبندی اینکه واقعاً چه چیزی تغییر کرده، که همان کاری است که AnalyzeModifications میکند. آن را به یک revision پیشین اشاره کنید، سپس GetModificationLevel را برای حکم کلی بخوانید و accessorهای بهازای هر یافته را برای سطح، شماره شیء و توصیف هر تفاوت
با جاافتادن این، اجرای DocMDP به یک مقایسه فرومیریزد: آیا سطح محاسبهشده در سطح مجاز خطمشی است یا پایینتر از آن
چرا انتظار میرود PDF امضاشده تغییر کند
سه مورد مشروع، و بیشتر آنچه خواهید دید را پوشش میدهند. امضاکننده دوم امضایش را اضافه میکند. یک گیرنده فیلدهای فرمی را که مؤلف باز گذاشته پر میکند. و مواد اعتبارسنجی بلندمدت پیوست میشود: پاسخهای OCSP و CRLها که در فروشگاه امنیتی سند نوشته میشوند تا امضا پس از ناپدیدشدن پاسخدهندهها همچنان قابل راستیآزمایی بماند. آن مورد آخر صرفاً مجاز نیست، کاری است که یک آرشیو خوشمدیریت عمداً با اسناد امضاشده انجام میدهد
پس «فایل بعد از امضا بزرگتر شد» هیچ اطلاعاتی حمل نمیکند. پرسش همیشه این است که چه چیزی اضافه شد، و پاسخ باید از مقایسه وضعیتهای سند بیاید نه از تماشای بایتها. مکانیک خود append در مقاله بهروزرسانی افزایشی پوشش داده شده است
طبقهبندی بر اساس شکل شیء، نه بر اساس مسیری که آن را تولید کرد
طبقهبند نگاه میکند که یک شیء پس از تغییر چیست، نه اینکه کدام فراخوانی کتابخانه آن را ساخته. این عمدی است، چون تحلیل روی فایلهای تولیدشده توسط نرمافزارهای دیگر اجرا میشود، جایی که هیچ مسیر فراخوانی برای بازرسی در دسترس نیست
چهار شکل شناخته میشود. دیکشنریهای اطلاعات فروشگاه امنیتی سند و اعتبارسنجی، آبجکتهای جریان مرجع متقاطع، entry متادیتای کاتالوگ، و دیکشنریهای امضا حامل یک بازه بایت، مواد آرشیو بلندمدتاند. شیءای که هم یک نوع فیلد و هم یک مقدار فیلد حمل کند پرکردن فرم است. شیءای که نوعش annotation باشد، یا زیرنوعش یکی از آنهای فهرستشده در جدول 168 از ISO 32000-2 باشد، یک تغییر حاشیهنویسی است. هر چیز دیگری طبقهبندینشده است
حذفها سختگیرانهتر از افزودنها برخورد میشوند. شیء حذفشده فقط وقتی whitelist میشود که شیء سمت قدیم خودش ماده آرشیو بوده، که حالت عادی جایگزینشدن فروشگاه امنیتی با یکی جدیدتر را پوشش میدهد. هر حذف دیگری طبقهبندینشده است، چون پاککردن محتوا از یک سند امضاشده چیزی نیست که یک سطح مجوز مجازش بداند. تفاوتهای در سطح سند سختگیرانهترند: تغییر در تعداد صفحات مستقیم به طبقهبندینشده میرود بدون بازرسی تکتک آبجکتها، چون هیچ سطح DocMDPای افزودن یا حذف صفحه را مجاز نمیداند
whitelist به سمت ردکردن خطا میکند
این همان قاعده طراحی است که بر هر تصمیم مرزی حکومت میکند. تغییری که بهغلط مجاز طبقهبندی شود امضایی است که روی محتوایی تأیید میشود که مؤلف هرگز مجازش نکرده بود. تغییری که بهغلط طبقهبندینشده طبقهبندی شود سندی است که پرچم میخورد و توسط یک انسان بازبینی میشود. این دو خطا متقارن نیستند، پس whitelist باریک میماند و شکلهای نشناخته بهجای حدسزدن به طبقهبندینشده میافتند
این یک پیامد عملی ارزش پیشبینی دارد: فایلهای تولیدکنندگان غیرمعمول گاهی تغییرات طبقهبندینشدهای را گزارش میکنند که در بازرسی بیخطرند. پاسخ درست نگاهکردن به جزئیات یافته و شماره شیء است نه پهنکردن whitelist، چون whitelistای که برای ساکتکردن گزارشهای تکی بزرگ شود دیگر یک کنترل امنیتی نیست
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؛ getter ترتیبی آن را برمیگرداند
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 آشکار میکند و تحلیل تغییرات روی آن ساخته شده، آبجکتها را با اثرانگشتی از بدنه نرمالشدهشان شناسایی میکند که از یک هش ۶۴بیتی غیر رمزنگارانه استفاده میکند نه SHA-256. این یک انتخاب سنجیده است. آنچه مقایسه ساختاری میخواهد قطعیت است: همان بدنه شیء باید همیشه در یک اجرا همان اثرانگشت را تولید کند. به مقاومت برخورد نیازی ندارد، چون مهاجمی که هر دو سمت مقایسه را کنترل میکند از قبل با راههای دیگر برده است، و پرداخت هزینه یک هش رمزنگارانه کامل روی هر شیء در سندی با یک میلیون شیء هزینه واقعی است بدون هیچ سودی
دو قاعده نرمالسازی بیشتر از انتخاب هش اهمیت دارند. ارجاعهای غیرمستقیم به یک توکن جاینگهدار فرومیپیچند بهجای آنکه به محتوای ارجاعشده باز شوند: بازکردن بدنه شیء مشترک را در هر ارجاعدهنده کپی میکرد، پس یک ویرایش کوچک روی یک font descriptor مشترک اثرانگشت هر شیءای که به آن میرسد را باطل میکرد، و گزارش خواننشدنی میشد. و شمارههای شیء خودشان از اثرانگشت مستثنیاند، چون یک بازنویسی میتواند آبجکتها را بدون تغییر هیچ چیز معنایی دوباره شمارهگذاری کند
سپس تطبیق در دو گذر اجرا میشود، نخست همترازسازی بر اساس اثرانگشت و سپس جفتکردن باقیمانده بر اساس شماره شیء برای شناسایی تغییر بهجای یک افزودن بهعلاوه یک حذف. کنترلهای ارزان سرتاسر اول میآیند: تفاوت تعداد صفحه پیش از آغاز هر پیمایش شیء گزارش میشود
یک تله: مقایسه خود با خود تضمینی برای یکسان بودن ندارد
طبیعیترین تست اول برای یک موتور دیف مقایسه یک فایل با خودش و ادعای یکسان بودن نتیجه است. آن ادعا اینجا برقرار نیست، و دلیلش آموزنده است. مسیر بارگذاری عمومی و مسیر بارگذاری سند سطح پایینتر decoding را یکسان پیکربندی نمیکنند، پس همان فایل که از دو مسیر بارگذاری شود میتواند اثرانگشتهایی متفاوت برای بعضی آبجکتها تولید کند. موتور غلط نیست؛ دو بارگذاری واقعاً وضعیتهای درونحافظه متفاوتی تولید کردهاند
بهجای آنکه دو مسیر را به زور به هم بچسبانیم، معناشناسی مقایسه بهشکل باریک بیان میشود: تحلیل وضعیت فعلی سند را با یک revision پیشین مقایسه میکند، و تنها وقتی یکسان گزارش میدهد که دو مجموعه اثرانگشت دقیقاً منطبق شوند. آن پرسشی است که کاربران واقعاً میپرسند، و نیازی ندارد دو لودر جایگزین هم باشند. وقتی در حال طراحی یک قابلیت مقایسه هستید، تعریف اینکه «یکسان» یعنی چه بیشتر از محاسبهاش کار است
کجا از آن استفاده کنیم
دو جا. در یک گزارش اعتبارسنجی، در کنار بررسی امضا، تا بازبین نهفقط ببیند امضا از نظر رمزنگارانه سالم است یا نه، بلکه ببیند پس از آن برای سند چه گذشته؛ سمت امضا در امضا و اعتبارسنجی PAdES پوشش داده شده. و در یک دروازه پذیرش، جایی که سندی که از بیرون میرسد با نسخهای که فرستادهاید کنترل میشود، تا قرارداد برگشتی با یک حاشیهنویسی اضافهشده جور دیگری برخورد شود تا قراردادی با یک صفحه ویرایششده
یک هشدار درباره دامنه. این تحلیل میگوید میان دو revision از همان تبار سند چه تغییر کرده. نمیگوید محتوای مرئی گمراهکننده است یا نه، اینکه جریان ظاهر فیلد فرم با مقدارش میخواند یا نه، یا اینکه متنی که زیر یک overlay پنهان شده هنوز در جریان محتوا هست یا نه. آنها به برخورد جداگانه نیاز دارند، و سمت حذف محتوای آن در مقاله redaction واقعی پوشش داده شده است. نقاط ورود تحلیل و مقایسه در صفحه محصول losLab PDF Developer Library مستند شدهاند