U PDFium Component buildovima pre v3.126.2, TPdf.AnalyzeSignatureRevisions mogao je da oceni pravu izmenu sadržaja stranice kao dozvoljenu izmenu anotacije pod DocMDP P=3, jer je njegov graf uloga revizija tretirao /P povratnu referencu signature widgeta na njegovu stranicu kao vlasništvo. Od v3.126.2 PDFium Component razdvaja navigacijske grane od grana u vlasništvu, pa sadržaj stranice ostaje sadržaj stranice. Prijava baga iza ove popravke deluje bezopasno na papiru. Sertifikovani ugovor dozvoljava anotacije, druga strana doda jedno inkrementalno čuvanje, i analizator kaže da je svaka kasnija izmena dozvoljena. Pa neko uporedi renderovane stranice i iznos plaćanja na stranici 2 je drugačiji
Ovaj tekst je nastavak s očima napadača teksta o pregledu analize promena revizija posle potpisa, pa preskače osnove obnove revizija i DocMDP ocenjivanja i ide pravo u graf objekata: kako je vlasništvo bilo modelovano, zašto smer jedne grane odlučuje o bezbednosnoj presudi, šta se promenilo u v3.126.2, i kako da audirate sopstvenu logiku prihvatanja
Zašto je izmena stranice prošla kao izmena anotacije pod DocMDP P=3?
Izmena stranice je prošla jer je stari graf uloga pratio svaku indirektnu referencu u rečniku kao da pripadajući objekat pripada onome koji ga referencira, a signature widget pokazuje nazad na svoju stranicu. Rečnik anotacije nosi /P, indirektnu referencu na objekat stranice na kojoj sedi (ISO 32000-1 §12.5.2). Taj unos je navigacijska naznaka. Widget ne poseduje stranicu; stranica poseduje widgeta kroz svoj niz /Annots
Analizator dodeljuje svakom objektu skup bitova uloga pre nego što oceni kasnije promene: stranica, anotacija, forma i materijal validacije. Korenski objekti dobijaju ulogu iz sopstvenog rečnika, i uloga se zatim širi na sve što referenciraju. U starom širenju lanac je išao ovako:
- Signature widget je
/Subtype /Widgets/FT /Sig, pa dobija ulogu anotacije /Pwidgeta gura ulogu anotacije na rečnik stranice, koji već ima ulogu stranice- Stranica gura obe uloge u
/Contents,/Resourcesi, kroz/Parent, gore u Pages stablo i preko svake sestrinske stranice - Rečnik toka sadržaja poput
<< /Length 812 >>nema/Type, pa je klasifikator pao na bitove uloga i proverio ulogu anotacije pre uloge stranice
Izmenjeni tok sadržaja je zato izašao kao prckAnnotation. Pod ISO 32000-1 §12.8.2.2 DocMDP P=3 dozvoljava izmene anotacija, pa je presuda bila prdAllowed i izveštaj se zbrinuo u prasAllowed. Isti fajl pod P=2 je odbijen, ali samo slučajno: P=2 zabranjuje izmene anotacija, pa je pogrešno označeni tok odbijen iz pogrešnog razloga. Fiksna petlja širenja u četiri prolaza dodala je i drugu slabost. Sadržaj koji stiže kroz indirektni niz, ili kroz dugi lanac čiji se brojevi objekata vraćaju unazad, možda nikad ne dobije nikakvu ulogu
Zašto validator potpisa mora da pita ko poseduje objekat?
Validator potpisa mora da pita ko poseduje objekat jer PDF inkrementalna ažuriranja (ISO 32000-1 §7.5.6) dozvoljavaju svakome da doda reviziju koja redefiniše postojeći broj objekta, i redefinisano telo ne najavljuje šta jeste. Potpis se i dalje verifikuje, jer pokriva samo bajtove svoje revizije. Svaka odbrana od manipulacije posle potpisivanja zato zavisi od preslikavanja svakog promenjenog objekta na strukturu koja ga koristi, i od pitanja da li je potpisnik dozvolio da se ta struktura menja
Nekoliko objavljenih klasa napada radi baš u tom rasponu. Napadi inkrementalnim čuvanjem dodaju reviziju koja zamenjuje sadržaj stranice i računaju na to da verifier proverava samo potpisani bajt-opseg. Shadow napadi sade skriveni sadržaj pre potpisivanja i aktiviraju ga posle malom, nevinom izmenom. Napadi na sertifikovane dokumente zloupotrebljavaju činjenicu da P=2 i P=3 eksplicitno dozvoljavaju neke kasnije izmene, pa zabranjenu izmenu obuku u dozvoljenu. Verifier koji klasifikuje objekte po oznakama poput /Type /Annot, ili po bilo kom referentnom putu koji slučajno dođe do njih, izložen je trećoj klasi: napadaču treba samo jedna dozvoljena struktura koja može da dopre do zabranjene
Zato pitanje nije koji su se objekti promenili nego ko ih poseduje. Tok sadržaja do koga se stiže sa stranice preko /Contents je sadržaj stranice ma šta još pokazivalo na njega. Anotacija koja pokazuje nazad na stranicu preko /P kaže gde anotacija živi, ne šta poseduje
Kako PDFium Component v3.126.2 modeluje vlasništvo?
PDFium Component v3.126.2 tretira povratne reference kao navigaciju, drži ih van širenja uloga, i odlučuje koji ključevi se računaju kao navigacija iz strukturne uloge rečnika koji ih nosi, ne iz samog imena ključa. Tabela sažima navigacijske ključeve koji više ne nose vlasništvo
| Vlasnički rečnik | Ključevi tretirani kao navigacija | Reference iz specifikacije |
|---|---|---|
| Stranica ili Pages čvor | /Parent, /Kids, /Annots | ISO 32000-1 §7.7.3 |
| Anotacija ili widget | /P | ISO 32000-1 §12.5.2 |
| Widget ili rečnik polja | /Parent | ISO 32000-1 §12.7.3 |
Filtriranje po imenu ključa globalno bi napravilo novu rupu. Font ili XObject resurs može legalno da se zove /P, /Parent ili /Annots, i /Resources rečnik koji bi izbacio svoj /P unos iz širenja dozvolio bi napadaču da sakrije objekat u vlasništvu stranice iza nevinog imena resursa. U v3.126.2 navigacijski filter primenjuje se samo kad vlasnički rečnik zaista jeste stranica, Pages čvor, anotacija, widget ili polje. Ako jedan od tih rečnika nosi duplirani navigacijski ključ, poput dva /P unosa u widgetu, analizator ne nagađa koju bi kopiju gledač koristio; izgradnja uloga pada i potpis postaje Indeterminate
Još nekoliko pravila zatvara preostale puteve preoznačavanja:
- Pages čvorovi su koreni uloge stranice sami po sebi, pa resursi nasleđeni iz Pages stabla (ISO 32000-1 §7.7.3.4) ulaze u kontekst stranice kroz pravo vlasništvo, a ne kroz
/Parentšetnju od dečje stranice - Uloga anotacije ili forme koja stigne do kataloga, Pages čvora, stranice, anotacije ili rečnika polja staje tu, jer ti strukturni objekti uspostavljaju sopstvene uloge i dolazna uloga sadržaja ne sme da ih pregazi
- Uloga stranice je autoritativna tokom klasifikacije: objekat u vlasništvu stranice je
prckPageContentčak i ako ga kasnija revizija prepiše s krivotvorenom/FT, oznakom/Type /Annot, ili ga podeli s tokom izgleda - Form XObject korišćen samo kao izgled polja ili anotacije zadržava svoju kategoriju forme ili anotacije, pa se obična obnova izgleda posle popunjavanja forme i dalje ocenjuje pod normalnim pravilima dozvola
- Widget bez sopstvenog
/FTrazrešuje nasleđeni tip polja kroz lanac/Parent-a, i nerazrešiv lanac obara izgradnju uloga umesto da podrazumeva anotaciju - Bitovi uloga iz svake kasnije revizije spajaju se u uloge pokrivene revizije, pa kasnije ažuriranje ne može da obriše raniji odnos vlasništva stranice tako što prvo otkaci tok pa ga posle menja
Fiksna tačka umesto fiksnog broja prolaza
Dohvatljivost uloga u v3.126.2 radi kao radni red koji se vrti dok nijedan objekat ne dobije novi bit uloge, što je prava fiksna tačka bez obzira na dubinu lanca ili numeraciju objekata. Indirektni nizovi poput /Contents niza sačuvanog kao sopstveni objekat takođe se prelaze. Svaki objekat može dobiti najviše četiri različita bita uloga, pa je red ograničen na četiri unosa po broju objekta; prekoračenje tog budžeta podiže prrResourceLimitExceeded. Referenca na slobodan objekat, nepoklapanje generacije ili pokvareno zaglavlje objekta podiže prrMalformedRevisionChain, a sadržaj unutar komprimovanog toka objekata prrCompressedObjectUnresolved. Svaki od tih neuspeha završava s prasIndeterminate, nikad s dozvoljenom presudom, i kad neuspeh nastane dok se grade uloge pokrivene revizije, potpis uopšte ne izveštava o Changes
Sledeća rutina nabraja izmene sadržaja stranice koje prežive ovu analizu. Promena prckPageContent se nikad ne ocenjuje kao prdAllowed: DocMDP P=1, 2 ili 3 je čini prdDisallowed, a potpis bez DocMDP-a je ocenjuje kao prdSuspicious
uses
SysUtils, TypInfo, PDFium, FPdfPades;
procedure ListPageContentEdits(const FileName: string);
const
ShadowTag: array[Boolean] of string = (' (unreferenced shadow)', '');
var
Pdf: TPdf;
Report: TPadesRevisionAnalysisReport;
Sig: TPadesSignatureRevisionAnalysis;
Change: TPadesRevisionObjectChange;
i, j: Integer;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := FileName;
Pdf.Active := True;
Report := Pdf.AnalyzeSignatureRevisions; // zapis, nema šta da se oslobodi
for i := 0 to High(Report.Signatures) do
begin
Sig := Report.Signatures[i];
if not (prrPageContentChanged in Sig.Risks) then
Continue;
Writeln(Format('Signature %d (DocMDP P=%d): page content changed',
[Sig.SignatureIndex, Sig.DocMdpPermission]));
for j := 0 to High(Sig.Changes) do
begin
Change := Sig.Changes[j];
if Change.Kind <> prckPageContent then
Continue;
Writeln(Format(' revision %d object %d %d R %s%s',
[Change.RevisionIndex, Change.ObjectNumber, Change.Generation,
GetEnumName(TypeInfo(TPadesRevisionDecision), Ord(Change.Decision)),
ShadowTag[Change.IsAuthoritative]]));
end;
end;
finally
Pdf.Free;
end;
end;
Šta se dešava kad FieldMDP i anotacija dele jedan objekat?
Kad /V polja i /Contents anotacije pokazuju na isti indirektni objekat, v3.126.2 zadržava FieldMDP bravu na snazi čak i kad se promena klasifikuje kao izmena anotacije. Scenario je lako napraviti rukom: potpisnik zaključava polje Total s FieldMDP-om (ISO 32000-1 §12.8.2.4), a napadač natera /Contents tekstualne anotacije da referencira isti string objekat koji drži vrednost polja. Pod P=3 izmena anotacije je dozvoljena, pa je pre popravke prepisivanje tog deljenog stringa promenilo zaključanu vrednost polja s dozvoljenom presudom
Objekat sada nosi i ulogu anotacije i ulogu forme, i presuda anotacije ponovo proverava stranu forme kad god potpis ima FieldMDP transformaciju:
- Pod P=2 izmena anotacije je ravno zabranjena, tačno kao pre
- S FieldMDP
All-om svako polje je zaključano, pa je deljena promenaprdDisallowed - S FieldMDP
IncludeiliExcludeanalizator ne može da prati deljeni skalar do jednog imena polja, pa je presudaprdIndeterminateumesto pogađanja - Bez FieldMDP-a važi pravilo anotacije P=3 i promena ostaje dozvoljena
Jedan detalj izveštavanja znači za gate kod. Deljeni slučaj izveštava se kao Kind = prckAnnotation s Decision = prdIndeterminate, a prrFieldMdpUnresolved se dodaje u skup rizika samo za promene klasifikovane kao polja forme. Gate koji traži prrFieldMdpUnresolved a ignoriše Status potpuno promašuje ovaj slučaj
Kako bi Delphi kod trebalo da pada zatvoren kod analize revizija?
Delphi kod bi trebalo da prihvati potpisani dokument samo kad je status analize prasNoLaterChanges ili prasAllowed i nema strukturnog rizika, i trebalo bi da tretira prasIndeterminate i prasSuspicious kao nepoverljive, ne kao upozorenja za logovanje i prolaz. Indeterminate znači da analizator nije mogao da dokaže da su kasnije revizije bile dozvoljene; za napadača je unos koji pouzdano daje Indeterminate jednako koristan kao onaj koji daje Allowed ako ga vaš kod pusti kroz. Globalni AnalyzePadesSignatureRevisions prima bilo koji TStream i čita ga od pozicije 0, što odgovara upload handlerima kojima nikad ne treba render dokumenta
uses
Classes, SysUtils, TypInfo, FPdfPades;
const
// Duplirane definicije se beleže bez spuštanja Status-a
BlockingRisks: TPadesRevisionRisks = [prrMalformedRevisionChain,
prrDuplicateObjectDefinition, prrUnreferencedObjectDefinition,
prrSignatureObjectRedefined, prrCompressedObjectUnresolved,
prrResourceLimitExceeded];
function SignedRevisionsAcceptable(const FileName: string;
out Reason: string): Boolean;
var
Source: TFileStream;
Report: TPadesRevisionAnalysisReport;
begin
Result := False;
Reason := '';
Source := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
Report := AnalyzePadesSignatureRevisions(Source);
finally
Source.Free;
end;
if Report.SignatureCount = 0 then
begin
Reason := 'no signature anchors the analysis';
Exit;
end;
if Report.Risks * BlockingRisks <> [] then
begin
Reason := 'structural risk in the revision chain';
Exit;
end;
case Report.Status of
prasNoLaterChanges, prasAllowed:
Result := True;
else
// prasIndeterminate i prasSuspicious su odbijanja, ne upozorenja
Reason := 'revision status ' +
GetEnumName(TypeInfo(TPadesRevisionAnalysisStatus), Ord(Report.Status));
end;
end;
Dve granice vredi je reći ravno. TPadesRevisionAnalysisReport ne kaže ništa o CMS celovitosti ni o poverenju u sertifikat, pa ova kapija sedi uz kriptografsku i trust validaciju, ne umesto njih. I ispravan graf vlasništva ne čini P=3 bezbednim za svaki tok rada. P=3 zaista dozvoljava anotacije, i anotacija s neprozirnim izgledom može da pokrije potpisani tekst a da ne dira nijedan tok sadržaja. Ako su vaši sertifikovani dokumenti ugovori, a ne kopije za pregled, ili sertifikujte s P=2, ili usmerite dozvoljene izmene anotacija čoveku, kao u ovom pomoćniku:
function AllowedAnnotationEditsUnderP3(
const Report: TPadesRevisionAnalysisReport): Integer;
var
i, j: Integer;
begin
Result := 0;
for i := 0 to High(Report.Signatures) do
if Report.Signatures[i].DocMdpPermission = 3 then
for j := 0 to High(Report.Signatures[i].Changes) do
if (Report.Signatures[i].Changes[j].Kind = prckAnnotation) and
(Report.Signatures[i].Changes[j].Decision = prdAllowed) then
Inc(Result);
end;
Lista za audit revizija potpisa
Iskoristite ovu listu da proverite da li je vaš verifikacioni pipeline bio izložen i da li sada pada zatvoren:
- Buildovi PDFium Component-a pre v3.126.2 mogli su izvestiti
prasAllowedza izmene sadržaja stranice u DocMDP P=3 dokumentima; ponovo pokreniteTPdf.AnalyzeSignatureRevisionsna sertifikovanim P=3 fajlovima prihvaćenim od starijih buildova - Ponovo proverite P=3 dokumente s FieldMDP bravama gde vrednost polja i anotacija mogu da dele indirektni objekat
- Prihvatite samo
prasNoLaterChangesiprasAllowed; tretirajteprasIndeterminateiprasSuspiciouskao nepoverljive - Testirajte
Report.Riskskao iReport.Status, jerprrDuplicateObjectDefinitionsam po sebi ne menja status - Ne čitajte prazan
Changesniz kao čist rezultat kad je status potpisa Indeterminate; pala izgradnja uloga ne izveštava o promenama - Ne oslanjajte se samo na
prrFieldMdpUnresolvedza hvatanje FieldMDP problema, pošto deljeni slučaj anotacije ispliva samo kroz presudu i status - Odlučite da li dozvoljene izmene anotacija pod P=3 treba ljudski pregled u vašem toku rada
- Analizirajte originalne bajtove fajla; dokument preređen s
SaveAs-om više ne sadrži lanac revizija
Analiza revizija je jedan sloj provere potpisa. Upairte je s pregledom PDF digitalnih potpisa i PAdES nivoa za rečnik i bazni nivo, i sa širim auditom PDF bezbednosnih rizika za JavaScript, launch akcije i ugrađene fajlove. TPdf.AnalyzeSignatureRevisions, AnalyzePadesSignatureRevisions i graf uloga svestan vlasništva opisan ovde isporučuju se u PDFium Component-u za Delphi, C++Builder i Lazarus