Technical Article

Bezpečná analýza PDF v pamäti: Ochrana pred škodlivými dokumentmi

Dokumenty PDF sú neuveriteľne mocné, no táto moc so sebou prináša neodmysliteľné bezpečnostné riziká. Pretože formát PDF podporuje vložené súbory, interaktívny JavaScript a komplexné binárne toky dát, často sa zneužíva ako vektor na šírenie malvéru. Pretečenie vyrovnávacej pamäte (buffer overflow), čítanie mimo hraníc a pretečenie celých čísel v zle navrhnutých analyzátoroch PDF môžu viesť k vzdialenému spusteniu kódu (RCE).

Ak budujete aplikáciu v Delphi, ktorá prijíma používateľmi nahrávané PDF (napríklad portál na príjem dokumentov), zaistenie pamäťovo bezpečnej analýzy PDF je kritickou bezpečnostnou požiadavkou.

Bežné vektory útoku cez PDF

Škodlivé dokumenty PDF zvyčajne cielia na zraniteľnosti v samotnom analyzátore, a nie na operačný systém. K bežným technikám patria:

  • Nesprávne sformátované tabuľky XRef (krížových odkazov): Vytvorenie ukazovateľov na ofsety, ktoré vedú mimo povolených hraníc, čo spôsobuje pád analyzátora alebo odhalenie obsahu pamäte.
  • Nekonečné slučky: Vytváranie kruhových odkazov medzi objektmi PDF (napríklad objekt A odkazuje na objekt B, ktorý zasa odkazuje na objekt A), čo vedie k vyčerpaniu kapacity zásobníka.
  • Explozívna dekompresia (Zip bomby): Použitie streamov typu FlateDecode, ktoré sa z niekoľkých kilobajtov rozbalia do gigabajtov, čím vyčerpajú systémovú pamäť.

Defenzívne stratégie analýzy v Delphi

Pri natívnom analyzovaní PDF v Delphi musíte programovať defenzívne. Nemôžete dôverovať metadátam poskytovaným v slovníkoch PDF.

1. Prerušenie kruhových odkazov

Pri rekurzívnom prechádzaní stromom objektov PDF si musíte udržiavať históriu navštívených objektov, aby ste zabránili nekonečným slučkám.

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. Ochrana pred Zip bombami

Pri aplikácii filtra FlateDecode na dekompresiu prúdu dát musíte striktne obmedziť maximálnu veľkosť expanzie. Nikdy neprideľujte pamäť naslepo iba na základe kľúča /Length v slovníku.

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;

Využitie zosilnených enginov a bezpečných komponentov

Napísať úplne bezpečný PDF parser od nuly je monumentálna úloha. Štandardným priemyselným prístupom je použitie zosilneného enginu, ktorý je silne testovaný metódou fuzzing, ako je PDFium, alebo spoliehanie sa na prísne testované natívne knižnice.

PDFium je hlavný renderovací engine používaný prehliadačom Google Chrome. Pretože Chrome denne spracováva milióny nedôveryhodných PDF, je PDFium vystavené agresívnemu a neustálemu fuzzingu od tímu Project Zero spoločnosti Google. Elegantne si poradí s poškodenými XRef tabuľkami, rozbitými streamami a cyklickými odkazmi.

Podobne aj natívne komponenty ako HotPDF Component a Delphi PDF Library obsahujú robustné defenzívne parsovacie stratégie už v základe. Implementujú prísnu kontrolu medzí, obmedzovače hĺbky rekurzie a mechanizmy na prevenciu úniku pamäte navrhnuté špeciálne pre prostredia Delphi a C++Builder.

Či už sa rozhodnete konzumovať PDFium cez Delphi wrapper na renderovanie, alebo využijete natívne komponenty ako HotPDF na generovanie a spracovanie dokumentov, zdedia bezpečnostný perimeter na podnikovej úrovni, ktorý ochráni vašich používateľov a servery pred škodlivým obsahom bez toho, aby ste museli sami písať defenzívne parsery.

Poznámka: Bezpečné parsovacie schopnosti preverené fuzzingom sú dostupné naprieč celou našou sadou, vrátane HotPDF Component, Delphi PDF Library a PDFium Component.