PDF dokumentai yra nepaprastai galingi, tačiau ši galia atneša būdingą saugumo riziką. Kadangi PDF failai palaiko įterptuosius failus, interaktyvų „JavaScript“ ir sudėtingus dvejetainius srautus, jie dažnai naudojami kaip kenkėjiškų programų platinimo vektoriai. Buferio perpildymai, skaitymai už ribų (angl. out-of-bounds reads) ir sveikųjų skaičių perpildymai prastai parašytuose PDF analizatoriuose gali lemti nuotolinį kodo vykdymą (angl. RCE).
Jei kuriate programą „Delphi“ aplinkoje, kuri priima vartotojų įkeltus PDF failus (pvz., dokumentų priėmimo portalą), atmintį saugančios (angl. memory-safe) PDF analizės užtikrinimas yra kritinis saugumo reikalavimas.
Dažni PDF atakų vektoriai
Kenkėjiški PDF failai paprastai taikosi į pažeidžiamumus pačiame analizatoriuje, o ne operacinėje sistemoje. Dažni metodai yra šie:
- Netinkamai suformuotos kryžminių nuorodų („XRef“) lentelės: rodyklių (angl. pointers) poslinkių konstravimas taip, kad jie išeitų už ribų, taip užlaužiant analizatorių arba leidžiant nutekinti atmintį.
- Begalinis ciklas: žiedinių nuorodų kūrimas tarp PDF objektų (pvz., objektas A nurodo į objektą B, kuris nurodo atgal į objektą A), dėl kurio išseikvojamas stekas.
- Sprogstantis dekompresavimas (užtrauktuko bombos, angl. Zip Bombs):
FlateDecodesrautai, kurie iš kelių kilobaitų išskleidžiami į gigabaitus, taip išsekinant sistemos atmintį.
Gynybinės analizės strategijos „Delphi“ aplinkoje
Analizuodami PDF natyviai „Delphi“ aplinkoje, privalote programuoti gynybiškai. Negalite pasitikėti metaduomenimis, pateiktais PDF žodynuose.
1. Žiedinių nuorodų nutraukimas
Rekursyviai eidami per PDF objektų medį, privalote išlaikyti aplankytų objektų istoriją, kad išvengtumėte begalinių ciklų.
uses
System.Generics.Collections, System.SysUtils;
// A safe recursive function to walk the PDF tree
procedure ParsePDFDictionary(DictObj: TPDFDictionary; Visited: TList<Integer>);
var
ObjID: Integer;
begin
ObjID := DictObj.ObjectID;
if Visited.Contains(ObjID) then
begin
Writeln('Warning: Circular reference detected. Aborting branch.');
Exit;
end;
Visited.Add(ObjID);
try
// Process child objects safely...
finally
// Allow siblings to traverse, but prevent vertical recursion loops
Visited.Remove(ObjID);
end;
end;
2. Apsauga nuo „Zip bombų“
Kai taikote FlateDecode filtrą srauto išskleidimui, privalote griežtai apriboti maksimalų išplėtimo dydį. Niekada nepriskirkite atminties aklai, remdamiesi /Length žodyno raktu.
const
MAX_DECOMPRESSED_SIZE = 1024 * 1024 * 50; // 50 MB safety limit
procedure DecompressPDFStream(CompressedStream, OutputTarget: TStream);
var
ZLibStream: TZDecompressionStream;
Buffer: array[0..8191] of Byte;
BytesRead, TotalRead: Integer;
begin
ZLibStream := TZDecompressionStream.Create(CompressedStream);
try
TotalRead := 0;
repeat
BytesRead := ZLibStream.Read(Buffer[0], SizeOf(Buffer));
if BytesRead > 0 then
begin
TotalRead := TotalRead + BytesRead;
if TotalRead > MAX_DECOMPRESSED_SIZE then
raise Exception.Create('Security Exception: Decompression bomb detected!');
OutputTarget.WriteBuffer(Buffer[0], BytesRead);
end;
until BytesRead = 0;
finally
ZLibStream.Free;
end;
end;
Sustiprintų variklių ir saugių komponentų panaudojimas
Visiškai saugaus PDF analizatoriaus rašymas nuo nulio yra monumentalus darbas. Standartinis pramonės požiūris yra naudoti sustiprintą, intensyviai fuzzingu testuotą variklį, pvz., PDFium, arba pasikliauti griežtai išbandytomis vietinėmis (native) bibliotekomis.
PDFium yra pagrindinis atvaizdavimo variklis, kurį naudoja „Google Chrome“. Kadangi „Chrome“ kasdien apdoroja milijonus nepatikimų PDF failų, „Google Project Zero“ PDFium nuolat ir agresyviai testuoja fuzzingu. Jis sklandžiai apdoroja netinkamai suformuotus XRef, sugadintus srautus ir ciklines nuorodas.
Panašiai, vietiniuose komponentuose, tokiuose kaip HotPDF Component ir Delphi PDF Library, standartiškai integruotos patikimos gynybinės analizės strategijos. Juose įdiegtas griežtas ribų tikrinimas, rekursyvaus gylio ribotuvai ir atminties nutekėjimo prevencijos mechanizmai, sukurti specialiai Delphi ir C++Builder aplinkoms.
Nesvarbu, ar pasirinksite naudoti PDFium per Delphi „wrapper“ atvaizdavimui, ar naudosite vietinius komponentus, tokius kaip HotPDF, dokumentų generavimui ir apdorojimui, jūs paveldėsite įmonės lygio saugos perimetrą, apsaugantį jūsų vartotojus ir serverius nuo kenkėjiškų naudingų apkrovų, jums patiems nereikės rašyti gynybinių analizatorių.
Pastaba: Saugios, fuzzingu testuotos analizės galimybės prieinamos visame mūsų rinkinyje, įskaitant HotPDF Component, Delphi PDF Library ir PDFium Component.