PDF nije samo papir. To je spremnik koji može nositi skripte koje se pokreću kada se datoteka otvori, veze koje pokreću vanjske programe, veze koje se obraćaju web poslužiteljima, datoteke ugniježđene unutar datoteka, te potpis koji tvrdi da se dokument nije promijenio otkako je netko jamčio za njega. Kada datoteka stigne iz izvora koji ne kontrolirate, najsigurniji prvi korak nije njezino prikazivanje. To je čitanje onoga što datoteka govori o sebi i izrada popisa svega što bi mogla pokušati učiniti, tako da čovjek može odlučiti pripada li ona uopće vašem tijeku rada.
Ovaj članak prolazi kroz statički prolaz revizije samo za čitanje preko te površine rizika koristeći PDFium komponentu za Delphi i Lazarus. Revizija nikada ne crta stranicu. Ona analizira strukturu dokumenta, popisuje dijelove datoteke koji nose ponašanje i piše jednostavno izvješće. To je razlika između traženja od stranca da isprazni džepove na vratima i povjerenja jer se nasmiješio.
Što je revizija, a što nije
Budite jasni oko granice. Pregled u pješčaniku (sandbox) iscrtava datoteku pod strogim ograničenjima kako bi je korisnik mogao pogledati bez da datoteka dotakne ostatak računala. Revizija dolazi prije toga. To je pregled bez iscrtavanja čiji je jedini izlaz opis površine prijetnje: koje skripte postoje, koje su akcije povezane s poveznicama, je li datoteka potpisana i koliko strogo, te što je priloženo. Pokrećete je kada dokument prijeđe granicu povjerenja, na ulazu iz e-pošte, obrasca za učitavanje ili partnerskog kanala, prije nego što je bilo koja kasnija faza stvarno otvori.
Komponenta učitava dokument na isti način za reviziju kao i za bilo što drugo. Postavite naziv datoteke i aktivirate je, što analizira podatke o unakrsnim referencama i katalog dokumenta bez iscrtavanja ijedne stranice. Sve u nastavku čita se iz tog učitanog, neiscrtanog stanja.
var
Pdf: TPdf;
begin
Pdf := TPdf.Create(nil);
try
Pdf.FileName := 'Incoming_Invoice.pdf';
Pdf.Active := True; // parses structure, renders nothing
// audit the loaded document here
finally
Pdf.Free;
end;
end;
JavaScript dokumenta u stablu naziva
Prva stvar koju treba popisati je kod. PDF može nositi JavaScript na razini dokumenta: skripte koje nisu priložene nijednoj stranici ili polju već samom dokumentu, pohranjene u stablu /Names pod unosom /JavaScript. Sukladan preglednik pokreće ih pri otvaranju. To je mehanizam iza dugog niza PDF zlonamjernih programa, jer omogućuje datoteci da izvrši logiku u trenutku kada korisnik dvoklikne na nju, prije nego što pročita ijednu riječ.
Revizor želi dvije činjenice o svakoj takvoj skripti: da postoji i što sadrži. Komponenta izlaže broj i omogućuje vam čitanje svake akcije kao zapisa koji sadrži naziv skripte i njezino cijelo tijelo. Čitanje tijela je važno. Skripta nazvana Doc.0 ne govori vam ništa, ali njezin tekst bi mogao pozvati app.launchURL ili sastaviti niz znakova i proslijediti ga tamo gdje ne bi smio ići. Izvlačenje izvornog koda kako bi ga recenzent mogao pročitati je cijela poanta označavanja datoteke koja pokreće kod pri otvaranju.
var
I: Integer;
Action: TPdfJavaScriptAction;
begin
if Pdf.JavaScriptActionCount > 0 then
WriteLn('WARNING: document runs ', Pdf.JavaScriptActionCount,
' script(s) on open');
for I := 0 to Pdf.JavaScriptActionCount - 1 do
begin
Action := Pdf.JavaScriptAction[I];
WriteLn(' script "', Action.Name, '":');
WriteLn(Action.Script); // full body, for a human to read
end;
end;
Datoteka s nula dokumentnih skripti nije automatski sigurna, jer postoje i skripte stranica i polja, ali datoteka s dokumentnim skriptama uvijek zaslužuje drugi pogled. Sam broj prisutnosti je koristan filtar, a tijelo je ono što filtar pretvara u procjenu.
Akcije pokretanja i URI akcije
Sljedeće ponašanje koje treba popisati živi na poveznicama i bilješkama. Dvije vrste akcija najvažnije su revizoru. Akcija pokretanja (Launch action) pokreće vanjski program ili otvara lokalnu datoteku kada se veza aktivira. URI akcija otvara web odredište. Recenzent koji gleda sumnjiv dokument trebao bi moći vidjeti, bez klikanja na bilo što, da je gumb na stranici tri povezan za pokretanje cmd.exe ili za otvaranje URL-a koji ne odgovara brendu na stranici.
Komponenta klasificira poveznice koje pronađe i izlaže vrstu akcije i ciljnu stazu za svaku, tako da revizija može izlistati svaku Launch i URI akciju s njezinim odredištem. Ovo je izvještavanje, a ne izvršavanje. Revizor čita akciju iz strukture i zapisuje je. Nikada je ne slijedi.
Kontrola preglednika koja iscrtava dokumente je mjesto gdje bi se praćenje akcije dogodilo, a njezino zadano držanje je namjerno oprezno. Kontrola TPdfView ima skup LinkOptions koji odlučuje koje se vrste veza automatski aktiviraju na klik. Njegova zadana vrijednost je [loAutoGoto, loAutoOpenURI], što znači da se skokovi unutar dokumenta i web URL-ovi mogu otvoriti, ali loAutoLaunch je odsutan, pa se akcije pokretanja nikada ne pokreću automatski. Za tijek rada revizije idete korak dalje i u potpunosti čistite taj skup, tako da se ništa uopće ne aktivira automatski dok još odlučujete hoćete li vjerovati datoteci.
// Audit posture for the viewer: nothing auto-runs, nothing auto-opens.
View.LinkOptions := [];
// The shipped default already withholds launch:
// default = [loAutoGoto, loAutoOpenURI]
// loAutoLaunch is NOT in the default set, so external programs
// are never started on a stray click out of the box.
Razlog iza uskraćivanja pokretanja po zadanim postavkama je jednostavan. Skok unutar dokumenta je bezopasan, a URL je vidljiv i može se otkazati, no pokretanje proizvoljnog vanjskog programa jednim klikom je najopasnija stvar koju PDF veza može tražiti, stoga je isključeno osim ako se sami ne odlučite za to. Revizor se isključuje čak i iz sigurnih ponašanja, jer je posao gledati, a ne djelovati.
Razina dopuštenja digitalnog potpisa MDP
Potpisi mijenjaju pitanje. Običan potpis svjedoči o bajtovima u vrijeme potpisivanja. Certifikacijski potpis, vrsta stvorena s pravilom za otkrivanje i sprječavanje izmjena dokumenta (MDP), ide dalje: on izjavljuje što se legitimno smije promijeniti nakon što je dokument certificiran, a sukladan preglednik upozorava ako je dotaknuto bilo što izvan tog dopuštenja. Čitanje te razine dopuštenja govori revizoru je li datoteka certificirana i, ako jest, koliko je čvrsto trebala biti zaključana.
MDP dopuštenje je cijeli broj s tri definirane vrijednosti. Razina 1 znači da promjene uopće nisu dopuštene; svaka izmjena narušava certifikaciju. Razina 2 dopušta popunjavanje obrazaca i potpisivanje, što je uobičajeni slučaj za ugovor koji treba dovršiti i potpisati, ali ne i mijenjati na drugi način. Razina 3 dodatno dopušta bilješke povrh popunjavanja obrazaca i potpisivanja. Poznavanje razine omogućuje vašoj ulaznoj logici da zaključi o namjeri: dokument certificiran na razini 1 koji unatoč tome sadrži polja obrasca ili skripte proturječi samome sebi, i to proturječje vrijedi označiti.
Komponenta čita broj potpisa i izlaže svaki kao zapis čije polje Permission nosi tu MDP vrijednost, popunjenu izravno iz temeljnog poziva FPDFSignatureObj_GetDocMDPPermission. Dopuštenje nula znači da potpis nije certifikacijski (DocMDP) potpis, pa stoga nema zaključavanja na razini dokumenta za prijavu.
var
I: Integer;
Sig: TPdfSignature;
begin
if Pdf.SignatureCount = 0 then
WriteLn('document is not signed')
else
for I := 0 to Pdf.SignatureCount - 1 do
begin
Sig := Pdf.Signature[I];
case Sig.Permission of
1: WriteLn('certified: no changes allowed');
2: WriteLn('certified: form fill and signing allowed');
3: WriteLn('certified: form fill, signing and annotations allowed');
else
WriteLn('signed, but not a DocMDP certification');
end;
end;
end;
Revizija ovdje ne provjerava kriptografiju potpisa; provjera lanca certifikata je zasebna briga. Ono što ona prijavljuje je deklarirana namjera: ova datoteka kaže da je zaključana na ovoj razini. To je točno kontekst koji recenzent treba kako bi procijenio jesu li kasnije promjene, ili samo prisustvo aktivnog sadržaja, u skladu s time kako je autor zapečatio dokument.
Ostatak površine: ugniježđene datoteke i XFA
Još dvije stavke zaokružuju potpuni popis. Ugniježđene datoteke (embedded files) su cijeli dokumenti koji se nose unutar PDF-a kao privici i oni su klasično vozilo za isporuku, jer izvješće benignog izgleda može isporučiti izvršnu datoteku ili drugi zlonamjerni PDF u svom stablu privitaka. Komponenta izlaže broj privitaka i naziv svakog privitka, tako da revizija može izlistati što sve putuje uz dokument bez izdvajanja ili otvaranja ičega od toga.
Prisutnost XFA je druga zastavica. XFA obrazac zamjenjuje statični AcroForm arhitekturom obrazaca temeljenom na XML-u koja donosi vlastiti model iscrtavanja i skriptiranja, veću i složeniju površinu od običnog obrasca. Ne morate obraditi XFA da biste primijetili da je tamo; njegova sama prisutnost je signal da datoteka nosi bogatiji interaktivni sloj vrijedan pažljivijeg pregleda. Komponenta to prijavljuje kao jednu booleovu vrijednost.
var
I: Integer;
begin
if Pdf.XFA then
WriteLn('NOTE: document contains an XFA form layer');
if Pdf.AttachmentCount > 0 then
begin
WriteLn('embedded files: ', Pdf.AttachmentCount);
for I := 0 to Pdf.AttachmentCount - 1 do
WriteLn(' - ', Pdf.AttachmentName[I]);
end;
end;
Jedna rutina samo za čitanje koja piše izvješće
Spojite dijelove i revizija je jedna procedura koja učitava dokument, popisuje njegove skripte i njihova tijela, navodi njegove Launch i URI ciljeve, prijavljuje MDP razinu potpisa, bilježi privitke i XFA, te zapisuje nalaze u zapisnik. Ne iscrtava ništa, pa je stoga jeftina i ne može se prevariti da prikaže neprijateljski sadržaj stranice. Izlaz je ravan, ljudima čitljiv zapis na koji recenzent ili nizvodno pravilo mogu djelovati.
Oblik koji dobro funkcionira u praksi je prikupljanje svakog nalaza kao retka, dodavanje prefiksa onima koji su doista rizični kako bi se razvrstali na vrh reda za pregled, te spremanje cijele stvari pored datoteke. Dokument bez skripti, bez akcija pokretanja, bez privitaka, bez XFA i ili bez potpisa ili s koherentnim certifikatom prolazi tiho. Dokument koji aktivira nekoliko zastavica odjednom je onaj koji bi osoba trebala vidjeti prije nego što ga bilo koja kasnija faza otvori. Revizija ne donosi odluku o povjerenju umjesto vas. Ona osigurava da je odluka informirana, a ne slijepa.
Jednom kada datoteka prođe reviziju i zaista je trebate pogledati, učinite to pod ograničenjem, a ne u zadanom pregledniku. Pristup u našem vodiču o izradi sigurnog pregleda PDF-a u Delphiu shows how to keep link auto-handling and active content from acting during a controlled look. To fold this enumeration into a full intake pipeline with reviewer tooling, see the PDF intake and review workbench article. Both build on the same read-only, render-free foundation and ship as part of the PDFium Component for Delphi and C++Builder, alongside the rendering, text, form, and signature APIs covered elsewhere on this blog.