Technical Article

Muistiturvallinen PDF-jäsennys: Puolustautuminen haitallisia asiakirjoja vastaan

PDF-asiakirjat ovat uskomattoman tehokkaita, mutta tähän tehokkuuteen liittyy luontaisia tietoturvariskejä. Koska PDF-tiedostot tukevat upotettuja tiedostoja, interaktiivista JavaScriptiä ja monimutkaisia binäärivirtoja, niitä käytetään usein haittaohjelmien levityskanavina. Puskurin ylivuodot, rajojen ulkopuoliset luvut ja kokonaislukujen ylivuodot huonosti kirjoitetuissa PDF-jäsentimissä voivat johtaa etäkoodin suorittamiseen (RCE).

Jos olet rakentamassa Delphi-sovellusta, joka hyväksyy käyttäjien lataamia PDF-tiedostoja (esim. asiakirjojen vastaanottoportaali), muistiturvallisen PDF-jäsennyksen varmistaminen on kriittinen tietoturvavaatimus.

Yleiset PDF-hyökkäysvektorit

Haitalliset PDF-tiedostot kohdistuvat yleensä itse jäsentimen haavoittuvuuksiin käyttöjärjestelmän sijaan. Yleisiä tekniikoita ovat:

  • Vääristyneet ristiinviittaustaulukot (XRef): Osoittimien siirtymien luominen, jotka johtavat rajojen ulkopuolelle, kaataen jäsentimen tai mahdollistaen muistin paljastumisen.
  • Päättymättömät silmukat: Kehäviittausten luominen PDF-objektien välille (esim. objekti A viittaa objektiin B, joka viittaa objektiin A), mikä johtaa pinon loppumiseen.
  • Räjähtävä purkaminen (Zip-pommit): FlateDecode-virrat, jotka purkautuvat muutamasta kilotavusta gigatavuihin kuluttaen järjestelmän muistin loppuun.

Puolustavat jäsennysstrategiat Delphissä

Kun jäsennetään PDF-tiedostoja natiivisti Delphissä, sinun on ohjelmoitava puolustavasti. Et voi luottaa PDF-sanakirjoissa annettuihin metatietoihin.

1. Kehäviittausten rikkominen

Kun käyt läpi PDF-objektipuuta rekursiivisesti, sinun on ylläpidettävä historiaa vierailuista objekteista päättymättömien silmukoiden estämiseksi.

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. Suojautuminen Zip-pommeja vastaan

Kun käytät FlateDecode-suodatinta virran purkamiseen, sinun on ehdottomasti rajoitettava laajentumisen enimmäiskokoa. Älä koskaan varaa muistia sokeasti perustuen /Length-sanakirja-avaimeen.

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;

Vahvistettujen moottoreiden ja turvallisten komponenttien hyödyntäminen

Täysin turvallisen PDF- jäsentimen kirjoittaminen alusta alkaen on valtava tehtävä. Alan vakiolähestymistapa on käyttää vahvistettua, raskaasti fuzz-testattua moottoria, kuten PDFiumia, tai luottaa tiukasti testattuihin natiivikirjastoihin.

PDFium on Google Chromen käyttämä ydinrenderöintimoottori. Koska Chrome käsittelee päivittäin miljoonia epäluotettavia PDF-tiedostoja, PDFium altistetaan Googlen Project Zeron aggressiiviselle ja jatkuvalle fuzz-testaukselle. Se käsittelee virheellisesti muotoillut XRefit, rikkoutuneet tietovirrat ja sykliset viittaukset sulavasti.

Samoin natiivikomponentit, kuten HotPDF Component ja Delphi PDF Library, sisältävät vankkoja puolustavia jäsennysstrategioita suoraan paketista. Ne toteuttavat tiukan rajatarkistuksen, rekursiivisen syvyyden rajoittimet ja muistivuotojen estomekanismit, jotka on suunniteltu erityisesti Delphi- ja C++Builder-ympäristöihin.

Riippumatta siitä, valitsetko PDFiumin kuluttamisen Delphi-kääreen kautta renderöintiin vai käytätkö natiivikomponentteja, kuten HotPDF:ää dokumenttien luomiseen ja käsittelyyn, perit yritystason tietoturvarajan, joka suojaa käyttäjiäsi ja palvelimiasi haitallisilta hyötykuormilta ilman, että sinun tarvitsee itse kirjoittaa puolustavia jäsentimiä.

Huomaa: Turvalliset, fuzz-testatut jäsennysominaisuudet ovat saatavilla koko tuotesarjassamme, mukaan lukien HotPDF Component, Delphi PDF Library ja PDFium Component.