Technical Article

Parsare PDF sigură pentru memorie: Apărarea împotriva documentelor malițioase

Documentele PDF sunt incredibil de puternice, dar acea putere vine cu riscuri inerente de securitate. Deoarece PDF-urile suportă fișiere încorporate, JavaScript interactiv și fluxuri binare complexe, acestea sunt frecvent utilizate ca vectori pentru livrarea de malware. Depășirile de buffer (buffer overflows), citirile în afara limitelor (out-of-bounds reads) și depășirile de numere întregi (integer overflows) în parsere PDF slab scrise pot duce la executarea de cod de la distanță (RCE).

Dacă construiți o aplicație în Delphi care acceptă PDF-uri încărcate de utilizator (de exemplu, un portal de preluare a documentelor), asigurarea unei parsări PDF sigure pentru memorie este o cerință critică de securitate.

Vectori comuni de atac PDF

PDF-urile malițioase vizează de obicei vulnerabilitățile din parserul însuși, mai degrabă decât din sistemul de operare. Tehnicile comune includ:

  • Tabele de referințe încrucișate (XRef) malformate: Crearea de decalaje de pointer care duc în afara limitelor, blocând parserul sau permițând divulgarea memoriei.
  • Bucle infinite: Crearea de referințe circulare între obiectele PDF (de exemplu, Obiectul A se referă la Obiectul B, care se referă la Obiectul A) ducând la epuizarea stivei (stack exhaustion).
  • Decompresie explozivă (Zip Bombs): Fluxuri FlateDecode care se decomprimă de la câțiva kiloocteți la gigaocteți, epuizând memoria sistemului.

Strategii de parsare defensivă în Delphi

Când parsați PDF-uri nativ în Delphi, trebuie să programați defensiv. Nu puteți avea încredere în metadatele furnizate în dicționarele PDF.

1. Întreruperea referințelor circulare

Când parcurgeți recursiv un arbore de obiecte PDF, trebuie să mențineți un istoric al obiectelor vizitate pentru a preveni buclele infinite.

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. Protecția împotriva bombelor Zip

Când aplicați filtrul FlateDecode pentru a decomprima un flux, trebuie să limitați strict dimensiunea maximă de expansiune. Nu alocați niciodată memorie orbește pe baza cheii de dicționar `/Length`.

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;

Valorificarea motoarelor consolidate și a componentelor sigure

Scrierea unui parser PDF complet securizat de la zero este o sarcină monumentală. Abordarea standard din industrie este de a utiliza un motor consolidat, testat riguros prin fuzzing, cum ar fi PDFium, sau de a vă baza pe biblioteci native testate riguros.

PDFium este principalul motor de randare utilizat de Google Chrome. Deoarece Chrome procesează zilnic milioane de fișiere PDF nesigure, PDFium este supus unui fuzzing agresiv și continuu de către Project Zero de la Google. Gestionează cu eleganță XRef-uri malformate, fluxuri întrerupte și referințe ciclice.

În mod similar, componentele native precum HotPDF Component și Delphi PDF Library încorporează din start strategii robuste de parsare defensivă. Acestea implementează verificări stricte ale limitelor, limitatoare de profunzime recursivă și mecanisme de prevenire a scurgerilor de memorie concepute special pentru mediile Delphi și C++Builder.

Fie că alegeți să consumați PDFium prin intermediul unui wrapper Delphi pentru randare, fie că utilizați componente native precum HotPDF pentru generarea și procesarea documentelor, moșteniți un perimetru de securitate la nivel de întreprindere, protejându-vă utilizatorii și serverele de încărcături malițioase fără a fi nevoie să scrieți propriile parsere defensive.

Notă: Capacitățile de parsare securizate, testate prin fuzzing, sunt disponibile în întreaga noastră suită, inclusiv în HotPDF Component, Delphi PDF Library și PDFium Component.