Pregledavanje nepouzdanog PDF-a unutar vaše vlastite aplikacije je sigurnosna odluka, a ono što je važno nije izgled preglednika, već ono što prozor odbija učiniti sam od sebe. Nemojte pisati datoteku na disk. Ne dopustite da njegove poveznice pokreću vanjske naredbe sustava. Ne dodjeljujte putanju njegovim privitcima. Najveći dio štete od zlonamjernog dokumenta ne dolazi od iskorištavanja propusta u pokretaču (exploit), već od preglednika koji radi sasvim uobičajene stvari s podacima koje je unio napadač: otvara file:// poveznicu prema UNC dijeljenom resursu (share) koja odaje NTLM vjerodajnice, ostavlja privremenu kopiju u temp direktoriju ili kopira ugrađene sadržaje kamo god ga naziv datoteke upućuje. PDFium komponenta (PDFium Component) je PDF preglednik s izvornim kodom za Delphi, C++Builder i Lazarus te stavlja važne prekidače tamo gdje ih možete dosegnuti: zastavica pri učitavanju koja gasi skriptiranje, događaji klika na poveznicu koje možete blokirati (veto), pristup privitcima koji ide kroz vaš vlastiti kod te bitovi dopuštenja koje možete čitati. Redoslijed u nastavku prati dokument od trenutka kada stigne do trenutka kada korisnik klikne nešto u njemu.
Model prijetnje prozora za pretpregled
Budite iskreni o tome što vam "siguran pretpregled" donosi. Rasterizator analizira nepouzdane bajtove bez obzira na to što radite, a sigurnost samog pokretača je temelj na kojem stojite. Sve iznad tog temelja je politika aplikacije: hoće li se skripte pokrenuti, što radi klik na poveznicu, mogu li ugrađene datoteke doći do diska, jesu li međuspremnik (clipboard) i pisač vrata ili zidovi. Jedna stvar koju treba rano otpisati je prekidač FPDF_SetSandBoxPolicy u samom pokretaču. Većina ograničenja pokretača je ugrađena pri kompajliranju, prekidač malo toga mijenja u praksi, a oslanjanje vaše priče o izolaciji na njega stvara samo lažan osjećaj da ste nešto učinili. Kada je unos uistinu neprijateljski, recimo javni portal za učitavanje datoteka, jedina stvarna izolacija je iscrtavanje u zasebnom procesu s niskim privilegijama i slanje bitmapa korisničkom sučelju. Zastavice unutar procesa su samo pravila ponašanja. One nisu izolacija (containment).
Dvije je površine lako zaboraviti upravo zato što ih nijedan klik nikada ne dotiče. Prva su privremene datoteke. Ako vaš cjevovod sprema dolazne dokumente na disk prije pretpregleda, te pripremljene kopije nadživjet će sesiju osim ako ih nešto pouzdano ne obriše, a datoteka koja se "može oporaviti iz privremenog direktorija" tiho je zaobišla svaku kontrolu koju sam prozor provodi. Umjesto toga, učitavajte iz memorije putem TPdfStreamAdapter, tako da zlonamjerni bajtovi nikada ne dobiju vlastitu putanju na disku. Druga površina je međuspremnik (clipboard). Pretpregled koji dopušta označavanje i kopiranje već je izvezao dokument, zaslon po zaslon, i nikakvo presretanje poveznica to neće spriječiti.
Onemogućite JavaScript pri učitavanju, a ne u korisničkom sučelju
JavaScript dokumenta u PDFium komponenti inicijalizira se samo zajedno s okruženjem za popunjavanje obrazaca. Učitavanje s postavkom FormFill := False stoga onemogućuje skriptiranje u samom korijenu umjesto suzbijanja njegovih simptoma:
procedure TPreviewPane.LoadUntrusted(const FilePath: string);
begin
Pdf.FileName := FilePath;
Pdf.FormFill := False; // no form environment, hence no JavaScript engine
Pdf.Active := True;
FPermissions := Pdf.Permissions; // raw flag word; all bits set = unrestricted
end;
Ovaj kompromis je stvaran i pripada vašoj specifikaciji. S isključenim popunjavanjem obrazaca nestaju i legitimne interakcije s AcroFormom i skripte za provjeru valjanosti; polja se iscrtavaju sa svojim zadnjim spremljenim izgledom, ali se ne mogu uređivati. Za prozor pretpregleda to je obično ispravna odluka, jer pretpregled znači gledanje, a ne popunjavanje. Ali ako isti prozor služi i kao površina za popunjavanje obrazaca za povjerljive interne dokumente, rješenje su dvije putanje učitavanja s jasnom odlukom o povjerenju između njih, a ne jedna putanja s kompromisnom postavkom koja je prelabava za zlonamjerni slučaj, a prestroga za povjerljivi. Strana popunjavanja obrazaca tog razdvajanja ima svoje zamke, pokrivene u članku o navigaciji kroz polja obrasca i regeneraciji izgleda.
Poveznice: zadani rukovatelj pokreće vanjske programe
Ako se ostave bez nadzora, klikovi na poveznice idu izravno u operativni sustav. Zadani LinkOptions preglednika uključuju opciju loAutoOpenURI, što je zapravo sigurnosni propust curenja s file:// na UNC dijeljene resurse koji samo čeka da se dogodi. Dva događaja čine usko grlo: OnWebLinkClick za URL-ove otkrivene u tekstu stranice i OnAnnotationLinkClick za anotacije poveznica koje nose URI ili akcije pokretanja. Postavite Handled := True u oba slučaja, bezuvjetno, prije donošenja bilo kakve odluke, a zatim dopustite samo ono što pravila dopuštaju. Kao drugi sloj zaštite, uklonite loAutoOpenURI iz LinkOptions za sumnjive unose i osigurajte da se loAutoLaunch, koji je prema zadanim postavkama isključen, nikada ne vrati kroz kopiranu konfiguraciju:
procedure TPreviewPane.PdfViewWebLinkClick(Sender: TObject;
const Url: WString; var Handled: Boolean);
begin
Handled := True; // never fall through to the default shell behavior
if (AnsiStartsText('https://', Url) or AnsiStartsText('http://', Url))
and HostIsAllowed(Url) then
OpenInBrowser(Url)
else
FAudit.LogBlockedLink(FDocumentId, Url);
end;
Dva detalja određuju hoće li ovo zapravo izdržati. Prvo, provjera sheme mora biti provjera prefiksa na sirovom nizu prije bilo kakvog parsiranja, jer su file://, UNC putanje i egzotične sheme upravo one vrijednosti koje ruše naivne URL parsere ili se provuku kroz one koji previše revno normaliziraju podatke. Drugo, bilježite svako blokiranje s pridruženim identitetom dokumenta. Nekoliko blokiranih file:// poveznica je pozadinski šum; nagli skok takvih blokiranja na većem broju dolaznih dokumenata u kratkom vremenu je incident o kojem bi vaš sigurnosni tim radije čuo od vas nego iz nekog drugog izvora.
Privitci: pravila o ekstenzijama i naziv datoteke koji niste sami odabrali
PDF je spremnik (kontejner), a AttachmentCount sa svojstvom AttachmentName[] govori vam što nosi prije nego što išta dotakne disk. Dvije zasebne kontrole su ovdje važne, a samo jedna od njih je očigledna. Očigledna je politika vrsta datoteka: bijeli popis (allowlist) ekstenzija koje se uopće smiju izvesti. Suptilna je činjenica da je naziv privitka podatak pod kontrolom napadača, bez iznimke. Ugrađeni naziv poput ..\..\Startup\update.exe pretvara neoprezno spremanje u prelazak putanje (path traversal) koji ubacuje izvršnu datoteku u mapu koju Windows pokreće pri prijavi. Komponenta vam predaje ugrađeni sadržaj u obliku bajtova kroz Attachment[] i omogućuje vašem kodu da odabere putanju, stoga izgradite tu putanju od očišćenog osnovnog naziva (basename), a nikada od sirovog ugrađenog niza:
procedure TPreviewPane.ExportAttachment(Index: Integer; const TargetDir: string);
var
RawName, SafeName, Ext: string;
Data: TBytes;
begin
RawName := string(Pdf.AttachmentName[Index]);
SafeName := ExtractFileName(RawName); // strips any path components
Ext := LowerCase(ExtractFileExt(SafeName));
if not FAllowedExt.Contains(Ext) then // allowlist, not blocklist
raise EPreviewPolicy.CreateFmt('Attachment type %s blocked by policy', [Ext]);
Data := Pdf.Attachment[Index]; // embedded payload as raw bytes
TFile.WriteAllBytes(
IncludeTrailingPathDelimiter(TargetDir) + SafeName, Data);
end;
Preferirajte smjer bijelog popisa (allowlist). Crni popis "opasnih" ekstenzija je utrka koju gubite onog dana kada netko iskoristi ekstenziju za koju nikada niste čuli; bijeli popis s .pdf, .png i .csv zatvara vrata za sve ostalo.
Što zapravo obećavaju dopuštenja šifriranja
Standardni sigurnosni rukovatelj prema ISO 32000-1 kodira zastavice dopuštenja za ispis, kopiranje sadržaja i izmjene, a svojstva Permissions i UserPermissions prikazuju ih kao sirove bitne maske čim se dokument otvori. ISO 32000-1 tablica 22 definira te bitove, a nešifrirana datoteka prijavljuje sve bitove postavljene. Čitajte ih i poštujte ih u svom naredbenom sloju, ali budite jasni o tome što oni zapravo jesu. Za dokument šifriran vlasničkom lozinkom i praznom korisničkom lozinkom, sadržaj se pri otvaranju u potpunosti dešifrira, a zastavice su tek zahtjev kompatibilnim preglednicima, a ne mehanizam prisile. To ima dvije posljedice koje vuku u suprotnim smjerovima. Nikada ne prezentirajte zastavice dopuštenja korisnicima kao sigurnosno svojstvo dokumenata koje primaju, jer oni to nisu. Istodobno, poštujte bit za ekstrakciju radi pristupačnosti (bit 10) čak i kada je opće kopiranje (bit 5) odbijeno; pristup čitačima zaslona namjerno je izdvojen u modelu dopuštenja i njegovo ukidanje jer je "kopiranje isključeno" kvari pomoćnu tehnologiju bez ikakvog sigurnosnog dobitka.
Provedite zabranjene radnje na razini naredbi, a ne skrivanjem gumba na alatnoj traci. Ctrl+C, kontekstni izbornici i povlačenje za odabir zaobilaze alatnu traku; jedna provjera dopuštenja unutar naredbe za kopiranje ne zaobilazi ništa.
Za dokumente koji zahtijevaju korisničku lozinku, dodijelite Password prije nego što postavite Active := True i tretirajte tu vrijednost kao tajnu što i jest: dohvatite je iz svoje pohrane vjerodajnica po sesiji, držite je izvan dnevnika i izvješća o rušenju te je nikada ne spremajte trajno pokraj dokumenta. Prozor za pretpregled koji predmemorira lozinke "radi praktičnosti" tiho je postao baza podataka lozinki bez ikakve odgovarajuće zaštite.
Ispis zaslužuje vlastitu odluku, a ne samo nasljeđivanje onoga na čemu se zaustavilo pravilo kopiranja. Fizički ispis je po definiciji nerevidiran, no potpuno blokiranje ispisa obično tjera korisnike prema snimkama zaslona, što je lošije na svakom polju. Uobičajeni kompromis je dopustiti ispis, ali na svakoj stranici otisnuti identitet korisnika i vremensku oznaku, što se provodi unutar same naredbe za ispis. Samo imajte ispravna očekivanja od toga: vodeni žig je sredstvo odvraćanja i atribucije. On nije prevencija.
Što vam je unos već trebao reći
Prozor za pretpregled donosi bolje odluke kada datoteka stigne s već priloženim dosjeom: je li šifrirana, je li JavaScript prisutan ili ne, popis privitaka, vrsta obrasca. Taj prolaz inspekcije pripada procesima prije samog preglednika, a uzorak u članku o izradi radnog stola za unos i pregled PDF-a proizvodi točno one zastavice koje sigurnosna pravila pretpregleda žele konzumirati. Datoteke koje je unos označio kao rizične automatski se otvaraju kroz zaštićenu putanju; uobičajeni dokumenti zadržavaju svoje pogodnosti. Povežite te dvije faze s jednim zajedničkim objektom pravila, radije nego s dva konfiguracijska zaslona koji će se razići do drugog izdanja bez obzira na to koliko ih pažljivo napisali prvi put.
Gdje se nalazi linija razgraničenja između procesa unutar same aplikacije (in-process) i izvan nje (out-of-process) ovisi o tome tko vam šalje datoteke. Za uobičajeni poslovni unos, ljudi koji šalju dokumente su poznati i samo neoprezni, pa je pretpregled unutar procesa s isključenim skriptiranjem i presretnutim poveznicama opravdana razina zaštite. Za anonimna javna učitavanja to nije slučaj, i nikakva količina postavljanja zastavica unutar procesa to neće promijeniti; takve datoteke iscrtavajte u zasebnom radnom procesu s niskim privilegijama i šaljite bitmape korisničkom sučelju, tako da vas propust u pokretaču košta samo radnog procesa, a ne same aplikacije. Donesite tu odluku o razdvajanju svjesno i zapišite u koju kategoriju pripada pojedina putanja unosa, jer je trošak pogrešne procjene asimetričan.
Licenciranje, API površina povezana sa sigurnošću i demonstracija zaštićenog preglednika nalaze se na stranici proizvoda: PDFium komponenta (PDFium Component).