Technical Article

Hukommelsessikker PDF-parsing: Forsvar mod ondsindede dokumenter

PDF-dokumenter er utroligt kraftfulde, men den kraft kommer med iboende sikkerhedsrisici. Fordi PDF'er understøtter indlejrede filer, interaktiv JavaScript og komplekse binære streams, bruges de ofte som vektorer for levering af malware. Bufferoverløb, læsninger uden for grænserne (out-of-bounds) og heltalsoverløb i dårligt skrevne PDF-parsere kan føre til fjernudførelse af kode (RCE).

Hvis du bygger en applikation i Delphi, der accepterer bruger-uploadede PDF'er (f.eks. en portal til dokumentindtagelse), er sikring af hukommelsessikker PDF-parsing et kritisk sikkerhedskrav.

Almindelige PDF-angrebsvektorer

Ondsindede PDF'er retter sig normalt mod sårbarheder i selve parseren frem for operativsystemet. Almindelige teknikker inkluderer:

  • Misdannede krydsreference-tabeller (XRef): Udformning af pointer-forskydninger, der fører uden for grænserne, hvilket får parseren til at gå ned eller tillader afsløring af hukommelse.
  • Uendelige sløjfer: Oprettelse af cirkulære referencer mellem PDF-objekter (f.eks. Objekt A refererer til Objekt B, som refererer til Objekt A), der fører til stak-udmattelse.
  • Eksploderende dekomprimering (Zip Bombs): FlateDecode-streams, der dekomprimeres fra et par kilobyte til gigabyte, hvilket udtømmer systemets hukommelse.

Defensive parsing-strategier i Delphi

Når du parser PDF'er indfødt i Delphi, skal du programmere defensivt. Du kan ikke stole på de metadata, der leveres i PDF-ordbøgerne.

1. Brydning af cirkulære referencer

Når du rekursivt gennemgår et PDF-objekttræ, skal du opretholde en historik over besøgte objekter for at forhindre uendelige sløjfer.

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. Beskyttelse mod Zip-bomber

Når du anvender FlateDecode-filteret til at dekomprimere en stream, skal du strengt begrænse den maksimale udvidelsesstørrelse. Tildel aldrig hukommelse blindt baseret på /Length-ordbogs-nøglen.

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;

Udnyttelse af hærdede motorer og sikre komponenter

At skrive en fuldstændig sikker PDF-parser fra bunden er en monumental opgave. Branchestandarden er at bruge en hærdet motor, der er stærkt fuzz-testet, som PDFium, eller at stole på strengt testede native biblioteker.

PDFium er den centrale renderingsmotor, der bruges af Google Chrome. Fordi Chrome behandler millioner af upålidelige PDF'er dagligt, udsættes PDFium for aggressiv, kontinuerlig fuzzing af Googles Project Zero. Den håndterer misdannede XRef'er, ødelagte strømme og cykliske referencer problemfrit.

På samme måde inkorporerer native komponenter som HotPDF Component og Delphi PDF Library robuste defensive parsingsstrategier direkte fra kassen. De implementerer streng grænsekontrol, rekursive dybdebegrænsere og mekanismer til forhindring af hukommelseslækager designet specifikt til Delphi- og C++Builder-miljøer.

Uanset om du vælger at forbruge PDFium via en Delphi-wrapper til rendering, eller udnytter native komponenter som HotPDF til dokumentgenerering og -behandling, arver du et sikkerhedsperimeter på virksomhedsniveau, der beskytter dine brugere og dine servere mod ondsindede payloads uden selv at skulle skrive defensive parsere.

Bemærk: Sikre, fuzz-testede parsingsfunktioner er tilgængelige på tværs af hele vores suite, herunder HotPDF Component, Delphi PDF Library og PDFium Component.