Technical Article

Memóriabiztonságos PDF-elemzés: Védekezés a rosszindulatú dokumentumok ellen

A PDF-dokumentumok hihetetlenül nagy tudásúak, de ez az erő eredendő biztonsági kockázatokkal jár. Mivel a PDF-ek támogatják a beágyazott fájlokat, az interaktív JavaScriptet és a komplex bináris streameket, gyakran használják őket kártevők bejuttatására (malware delivery vector). A rosszul megírt PDF-elemzőkben (parsers) a puffer-túlcsordulások (buffer overflows), a határokon kívüli olvasások (out-of-bounds reads) és az egész-túlcsordulások (integer overflows) távoli kódvégrehajtáshoz (RCE - Remote Code Execution) vezethetnek.

Ha olyan alkalmazást épít Delphiben, amely felhasználók által feltöltött PDF-eket fogad be (pl. egy dokumentumbeviteli portál), a memóriabiztonságos PDF-elemzés biztosítása kritikus biztonsági követelmény.

Gyakori PDF támadási vektorok

A rosszindulatú PDF-ek általában magában az elemzőben lévő sebezhetőségeket célozzák meg, nem pedig az operációs rendszert. A gyakori technikák a következők:

  • Hibásan formázott kereszthivatkozási (XRef) táblák: Olyan mutatóeltolások (pointer offsets) készítése, amelyek a memóriahatárokon kívülre mutatnak, összeomlasztva az elemzőt vagy lehetővé téve a memóriatartalom kiszivárogtatását.
  • Végtelen ciklusok (Infinite Loops): Körkörös hivatkozások létrehozása PDF-objektumok között (pl. az 'A' objektum hivatkozik a 'B' objektumra, ami pedig visszahivatkozik az 'A' objektumra), ami veremkimerüléshez (stack exhaustion) vezet.
  • Robbanó kicsomagolás (Zip bombák): Olyan FlateDecode streamek, amelyek néhány kilobájtról gigabájtokra bomlanak ki, kimerítve a rendszermemóriát.

Védekező elemzési stratégiák Delphiben

Amikor natívan elemez PDF-eket Delphiben, védekező (defensive) módon kell programoznia. Nem bízhat meg a PDF szótárakban megadott metaadatokban.

1. Körkörös hivatkozások megszakítása

Amikor rekurzívan bejár egy PDF-objektumfát, a végtelen ciklusok elkerülése érdekében fenn kell tartania a már meglátogatott objektumok előzményeit.

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. Védekezés a Zip bombák ellen

Amikor a FlateDecode szűrőt (filter) alkalmazza egy stream kicsomagolására, szigorúan korlátoznia kell a maximális kiterjedési méretet (expansion size). Soha ne foglaljon memóriát vakon a /Length szótárkulcs alapján.

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;

Megerősített motorok és biztonságos komponensek kiaknázása

Egy teljesen biztonságos PDF értelmező nulláról történő megírása monumentális feladat. Az iparági szabvány szerinti megközelítés egy megerősített, intenzíven fuzz-tesztelt motor, például a PDFium használata, vagy pedig szigorúan tesztelt natív könyvtárakra való támaszkodás.

A PDFium a Google Chrome által használt alapvető renderelő motor. Mivel a Chrome naponta több millió nem megbízható PDF-et dolgoz fel, a PDFiumot a Google Project Zero csapata agresszív, folyamatos fuzzingnak veti alá. Elegánsan kezeli a hibás XRef-eket, a megszakadt streameket és a ciklikus hivatkozásokat.

Hasonlóképpen, az olyan natív komponensek, mint a HotPDF Component és a Delphi PDF Library már a dobozból kivéve robusztus defenzív értelmezési stratégiákat tartalmaznak. Szigorú határellenőrzést, rekurzív mélységkorlátozókat és memóriaszivárgást megelőző mechanizmusokat implementálnak, amelyeket kifejezetten Delphi és C++Builder környezetekhez terveztek.

Akár a PDFiumot választja egy Delphi wrapperen keresztül történő rendereléshez, akár olyan natív komponenseket használ dokumentumgenerálásra és -feldolgozásra, mint a HotPDF, nagyvállalati szintű biztonsági perimetert örököl, megvédve felhasználóit és szervereit a rosszindulatú rakományoktól anélkül, hogy önmagának kellene defenzív értelmezőket írnia.

Megjegyzés: A biztonságos, fuzz-tesztelt értelmezési képességek a teljes termékcsaládunkban elérhetők, beleértve a HotPDF Component-et, a Delphi PDF Library-t és a PDFium Component-et.