Technical Article

Analyse de PDF sécurisée en mémoire : défense contre les documents malveillants

Les documents PDF sont incroyablement puissants, mais cette puissance s'accompagne de risques de sécurité inhérents. Étant donné que les PDF prennent en charge les fichiers intégrés, le JavaScript interactif et les flux binaires complexes, ils sont fréquemment utilisés comme vecteurs de diffusion de logiciels malveillants. Les dépassements de mémoire tampon, les lectures hors limites et les dépassements d'entiers dans les analyseurs PDF mal écrits peuvent entraîner l'exécution de code à distance (RCE).

Si vous créez une application dans Delphi qui accepte des PDF téléchargés par les utilisateurs (par exemple, un portail d'ingestion de documents), garantir une analyse de PDF sécurisée en mémoire est une exigence de sécurité critique.

Vecteurs d'attaque PDF courants

Les PDF malveillants ciblent généralement des vulnérabilités dans l'analyseur lui-même plutôt que dans le système d'exploitation. Les techniques courantes incluent :

  • Tables de références croisées (XRef) mal formées : Création de décalages de pointeur qui mènent hors limites, ce qui fait planter l'analyseur ou permet la divulgation de mémoire.
  • Boucles infinies : Création de références circulaires entre des objets PDF (par exemple, l'objet A fait référence à l'objet B, qui fait référence à l'objet A) entraînant l'épuisement de la pile.
  • Décompression explosive (Bombes Zip) : Flux FlateDecode qui se décompressent de quelques kilo-octets à plusieurs gigaoctets, épuisant la mémoire système.

Stratégies d'analyse défensive dans Delphi

Lors de l'analyse native de PDF dans Delphi, vous devez programmer de manière défensive. Vous ne pouvez pas faire confiance aux métadonnées fournies dans les dictionnaires PDF.

1. Briser les références circulaires

Lors du parcours récursif d'une arborescence d'objets PDF, vous devez conserver un historique des objets visités pour éviter les boucles infinies.

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. Protection contre les bombes Zip

Lors de l'application du filtre FlateDecode pour décompresser un flux, vous devez limiter strictement la taille d'extension maximale. N'allouez jamais de mémoire à l'aveugle en vous basant sur la clé de dictionnaire `/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;

Exploitation de moteurs renforcés et de composants sécurisés

Écrire un analyseur syntaxique PDF complètement sécurisé à partir de zéro est une tâche monumentale. L'approche standard de l'industrie consiste à utiliser un moteur renforcé et intensément testé par fuzzing comme PDFium, ou à s'appuyer sur des bibliothèques natives rigoureusement testées.

PDFium est le principal moteur de rendu utilisé par Google Chrome. Parce que Chrome traite quotidiennement des millions de PDF non fiables, PDFium est soumis à un fuzzing agressif et continu par le Project Zero de Google. Il gère gracieusement les XRefs malformés, les flux rompus et les références cycliques.

De même, les composants natifs tels que le HotPDF Component et la Delphi PDF Library intègrent par défaut de robustes stratégies d'analyse défensive. Ils mettent en œuvre des vérifications de limites strictes, des limiteurs de profondeur récursive et des mécanismes de prévention des fuites de mémoire conçus spécifiquement pour les environnements Delphi et C++Builder.

Que vous choisissiez de consommer PDFium via un wrapper Delphi pour le rendu, ou d'utiliser des composants natifs comme HotPDF pour la génération et le traitement de documents, vous héritez d'un périmètre de sécurité de niveau entreprise, protégeant vos utilisateurs et vos serveurs contre les charges utiles malveillantes sans avoir à écrire vous-même des analyseurs défensifs.

Remarque : Des capacités d'analyse sécurisées et testées par fuzzing sont disponibles dans l'ensemble de notre suite, y compris le HotPDF Component, la Delphi PDF Library et le PDFium Component.

\n