Technical Article

Minnesikker PDF-parsing: Forsvar mot ondsinnede dokumenter

PDF-dokumenter er utrolig kraftige, men den kraften kommer med iboende sikkerhetsrisikoer. Fordi PDF-filer støtter innebygde filer, interaktiv JavaScript og komplekse binærstrømmer, blir de ofte brukt som vektorer for spredning av skadelig programvare. Bufferoverflyt, lesing utenfor grenser og heltallsoverflyt i dårlig skrevne PDF-parsere kan føre til ekstern kodekjøring (RCE).

Hvis du bygger en applikasjon i Delphi som aksepterer PDF-filer lastet opp av brukere (for eksempel en portal for innhenting av dokumenter), er det et kritisk sikkerhetskrav å sikre minnesikker PDF-parsing.

Vanlige angrepsvektorer for PDF

Ondsinnede PDF-filer retter seg vanligvis mot sårbarheter i selve parseren fremfor operativsystemet. Vanlige teknikker inkluderer:

  • Misdannede Cross-Reference (XRef) tabeller: Utforming av pekerforskyvninger som fører utenfor grenser, får parseren til å krasje eller tillater minneavsløring.
  • Uendelige løkker: Oppretting av sirkulære referanser mellom PDF-objekter (f.eks. Objekt A refererer til Objekt B, som refererer til Objekt A) som fører til at stakken tømmes.
  • Eksploderende dekomprimering (zip-bomber): FlateDecode-strømmer som dekomprimeres fra noen få kilobyte til gigabyte og tømmer systemminnet.

Defensive parsestrategier i Delphi

Når du parser PDF-filer nativt i Delphi, må du programmere defensivt. Du kan ikke stole på metadataene som er gitt i PDF-ordbøkene.

1. Bryte sirkulære referanser

Når du rekursivt går gjennom et PDF-objekttre, må du opprettholde en historikk over besøkte objekter for å forhindre uendelige løkker.

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. Beskytte mot zip-bomber

Når du bruker FlateDecode-filteret for å dekomprimere en strøm, må du strengt begrense den maksimale utvidelsesstørrelsen. Du må aldri tildele minne blindt basert på /Length-ordboknøkkelen.

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;

Utnyttelse av herdede motorer og sikre komponenter

Å skrive en fullstendig sikker PDF-parser fra bunnen av er en enorm oppgave. Bransjestandarden er å bruke en herdet, sterkt fuzz-testet motor som PDFium, eller stole på grundig testede native-biblioteker.

PDFium er kjerne-rendringsmotoren som brukes av Google Chrome. Fordi Chrome behandler millioner av upålitelige PDF-filer daglig, blir PDFium utsatt for aggressiv, kontinuerlig fuzzing av Googles Project Zero. Den håndterer misdannede XRef-er, ødelagte strømmer og sykliske referanser på en elegant måte.

På samme måte har native-komponenter som HotPDF Component og Delphi PDF Library robuste defensive parsestrategier innebygd. De implementerer streng grensekontroll, rekursive dybdebegrensere og mekanismer for å forhindre minnelekkasje designet spesielt for Delphi- og C++Builder-miljøer.

Enten du velger å bruke PDFium via en Delphi-wrapper for gjengivelse, eller benytte native-komponenter som HotPDF for dokumentgenerering og -behandling, arver du en sikkerhetssone i bedriftsklasse som beskytter brukerne dine og serverne dine mot ondsinnede nyttelaster uten at du trenger å skrive defensive parsere selv.

Merk: Sikre, fuzz-testede parsing-funksjoner er tilgjengelige over hele pakken vår, inkludert HotPDF Component, Delphi PDF Library og PDFium Component.