O semnătură peste un PDF nu interzice schimbările ulterioare. Ea fixează un interval de octeți, iar un update incremental adaugă octeți noi după el, astfel încât semnătura rămâne matematic validă în timp ce documentul capătă conținut nou. Dacă acel conținut este acceptabil este o întrebare de politică, iar DocMDP este locul în care autorul enunță politica: nicio schimbare deloc, doar completare de formulare și semnare, ori acelea plus adnotări. Aplicarea ei înseamnă clasificarea a ceea ce s-a schimbat efectiv, iar asta face AnalyzeModifications. Îndreptați-o spre o revizie anterioară, apoi citiți GetModificationLevel pentru verdictul general și accessorii per constatare pentru nivelul, numărul de obiect și descrierea fiecărei diferențe
Cu acest mecanism la loc, aplicarea DocMDP se colapsează într-o comparație: nivelul calculat este la sau sub nivelul pe care politica îl permite
De ce se așteaptă ca un PDF semnat să se schimbe
Trei cazuri legitime, și ele acoperă majoritatea a ce veți vedea. Un al doilea semnatar își adaugă semnătura. Un destinatar completează câmpurile de formular lăsate deschise de autor. Iar materialul de validare pe termen lung este adăugat: răspunsuri OCSP și CRL scrise în document security store pentru ca semnătura să rămână verificabilă și după ce respondenții dispăr. Acesta din urmă nu este doar permis, este ceea ce o arhivă bine gestionată face intenționat cu documentele semnate
Deci „fișierul a crescut după semnare" nu poartă nicio informație. Întrebarea este întotdeauna ce a fost adăugat, iar răspunsul trebuie să vină din compararea stărilor documentului, nu din observarea octeților. Mecanica append în sine este tratată în articolul despre update incremental
Clasificați după forma obiectului, nu după calea care l-a produs
Clasificatorul privește ce este un obiect după schimbare, nu care apel de bibliotecă l-a creat. Este intenționat, deoarece analiza rulează pe fișiere produse de alt software, unde nu există niciun apel de inspectat
Patru forme sunt recunoscute. Dicționarele de informații document security store și legate de validare, obiectele de stream de referință încrucișată, intrarea metadata a catalogului și dicționarele de semnătură care poartă un interval de octeți sunt material de arhivă pe termen lung. Un obiect care poartă atât un tip de câmp, cât și o valoare de câmp este completare de formulare. Un obiect al cărui tip este annotation, sau al cărui subtype este unul dintre cele listate în ISO 32000-2 Table 168, este o schimbare de adnotare. Orice altceva este unclassified
Eliminările sunt tratate mai strict decât adăugările. Un obiect eliminat este trecut pe lista albă doar când obiectul din partea veche era el însuși material de arhivă, ceea ce acoperă cazul normal al unui security store înlocuit de unul mai nou. Orice altă eliminare este unclassified, deoarece ștergerea de conținut dintr-un document semnat nu este ceva pe care un nivel de permisiune îl autorizează. Diferențele la nivel de document sunt și mai stricte: o schimbare a numărului de pagini merge direct la unclassified fără examinarea obiectelor individuale, deoarece niciun nivel DocMDP nu permite adăugarea sau eliminarea de pagini
Lista albă greșează spre refuz
Aceasta este regula de design care guvernează fiecare decizie la limită. O schimbare clasificată greșit drept permisă este o semnătură care validează peste conținut pe care autorul nu l-a autorizat niciodată. O schimbare clasificată greșit drept unclassified este un document care este semnalat și revizuit de o persoană. Acele două erori nu sunt simetrice, deci lista albă rămâne îngustă, iar formele nerecunoscute cad în unclassified în loc să fie ghicite
Aceasta are o consecință practică care merită anticipată: fișierele de la producători neobișnuiti vor raporta uneori schimbări unclassified care, la inspecție, sunt benigne. Răspunsul corect este să priviți detaliile constatării și numărul de obiect, nu să lărgiți lista albă, deoarece o listă albă care crește pentru a tăcea rapoartele individuale încetează să fie un control de securitate
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 ordonat mlNone, mlLTAUpdates, mlFormFilling,
// mlAnnotations, mlUnclassified; getterul returnează ordinalul său
Level := Pdf.GetModificationLevel;
// Aplicarea DocMDP este acum o singură comparație cu politica
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;
Nivelul general este maximul peste toate constatările, ceea ce este singura agregare apărabilă: un document care conține nouăzeci și nouă de adăugări de arhivă și o schimbare unclassified este o schimbare unclassified
Sub capotă: amprente, nu hash-uri criptografice
Motorul de comparație pe care îl expune CompareWith, și pe care analiza modificărilor este construită, identifică obiectele printr-o amprentă a corpului lor normalizat folosind un hash pe 64 de biți necriptografic în loc de SHA-256. Este o alegere chibzuită. Ce are nevoie comparația structurală este determinism: același corp de obiect trebuie să producă întotdeauna aceeași amprentă în cadrul unei rulări. Nu are nevoie de rezistență la coliziuni, deoarece un atacator care controlează ambele părți ale comparației a câștigat deja prin alte mijloace, iar plata unui hash criptografic complet pentru fiecare obiect dintr-un document cu un milion de obiecte este un cost real fără niciun beneficiu
Două reguli de normalizare contează mai mult decât alegerea hash-ului. Referințele indirecte se pliază pe un token de substituție în loc să fie expandate în conținutul referențiat: expandarea ar copia corpul unui obiect partajat în fiecare referențiator, deci o mică editare a unui descriptor de font partajat ar invalida amprenta fiecărui obiect care ajunge la el, iar raportul ar fi ilizibil. Iar numerele de obiect în sine sunt excluse din amprentă, deoarece o rescriere poate renumera obiectele fără să schimbe nimic semantic
Potrivirea rulează apoi în două treceri, aliniind întâi după amprentă și perechind restul după numărul de obiect pentru a identifica schimbări, nu o adăugare plus o eliminare. Verificările ieftine vin primele peste tot: o diferență de număr de pagini este raportată înainte ca orice traversare de obiecte să înceapă
O capcană: autocompararea nu este garantată identică
Primul test natural pentru un motor de diff este să comparați un fișier cu el însuși și să afirmați că rezultatul este identic. Afirmația nu se susține aici, iar motivul este edificator. Calea publică de încărcare și calea de încărcare a documentului de nivel inferior nu configurează decodarea identic, deci același fișier încărcat prin cele două rute poate produce amprente care diferă pentru unele obiecte. Motorul nu greșește; cele două încărcări au produs efectiv stări diferite în memorie
În loc să forțeze cele două căi împreună, semantica comparației este enunțată îngust: analiza compară starea curentă a documentului cu o revizie anterioară și raportează identic doar când cele două seturi de amprente coincid exact. Aceasta este întrebarea pe care utilizatorii o pun efectiv, și nu cere ca cei doi loaderi să fie interschimbabili. Când proiectați o funcție de comparație, definirea a ceea ce înseamnă „același" este mai mult din muncă decât calcularea ei
Unde să îl folosiți
Două locuri. Într-un raport de validare, alături de verificarea semnăturii, astfel încât un revizitor vede nu doar dacă semnătura este criptografic intactă, ci și ce s-a întâmplat cu documentul după; partea de semnătură este tratată în semnarea și validarea PAdES. Și într-o poartă de primire, unde un document sosit din exterior este verificat față de copia pe care ați trimis-o, astfel încât un contract returnat cu o adnotare adăugată este tratat diferit de unul cu o pagină editată
O rezervă privind sfera. Această analiză vă spune ce s-a schimbat între două revizii ale aceleiași linii de document. Nu vă spune dacă conținutul vizibil este înșelător, dacă stream-ul de aspect al unui câmp de formular corespunde valorii lui, sau dacă textul ascuns sub un overlay este încă prezent în content stream. Acestea au nevoie de tratament separat, iar partea de eliminare de conținut este tratată în articolul despre redaction adevărat. Punctele de intrare de analiză și comparație sunt documentate pe pagina de produs losLab PDF Developer Library