PDF 文件非常強大,但這種強大伴隨著固有的安全風險。由於 PDF 支援內嵌檔案、互動式 JavaScript 與複雜的二進位串流,它們經常被用作傳遞惡意軟體的媒介。在寫得不好的 PDF 解析器中,緩衝區溢位、超出邊界讀取和整數溢位可能導致遠端執行程式碼 (RCE)。
如果您正在 Delphi 中建置接受使用者上傳 PDF 的應用程式 (例如文件接收入口網站),確保記憶體安全的 PDF 解析是一項關鍵的安全要求。
常見的 PDF 攻擊載體
惡意的 PDF 通常以解析器本身的漏洞為目標,而不是作業系統。常見技術包括:
- 格式不良的交叉參照 (XRef) 表格:製作超出邊界的指標偏移量,使解析器當機或允許記憶體洩漏。
- 無限迴圈:在 PDF 物件之間建立循環參照 (例如:物件 A 參照物件 B,物件 B 參照物件 A),導致堆疊耗盡。
- 爆炸式解壓縮 (Zip 炸彈):從幾 KB 解壓縮成數 GB 的 FlateDecode 串流,耗盡系統記憶體。
Delphi 中的防禦性解析策略
在 Delphi 中原生解析 PDF 時,您必須進行防禦性程式設計。您不能信任 PDF 字典中提供的詮釋資料。
1. 打破循環參照
遞迴遍歷 PDF 物件樹時,您必須維護一個已造訪物件的記錄,以防止發生無限迴圈。
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. 防禦 Zip 炸彈
套用 FlateDecode 過濾器解壓縮串流時,您必須嚴格限制最大的擴展大小。絕對不要盲目地根據 `/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;
善用加固引擎與安全元件
從零開始撰寫一個完全安全的 PDF 解析器是一項浩大的專案。業界標準的作法是使用經過深度模糊測試(fuzz-tested)的加固引擎,如 PDFium,或依賴經過嚴格測試的原生函式庫。
PDFium 是 Google Chrome 使用的核心彩現引擎。由於 Chrome 每天處理數以百萬計的不可信 PDF,PDFium 受到 Google Project Zero 持續而猛烈的模糊測試。它能夠從容地處理格式錯誤的 XRef、損壞的串流與循環參照。
同樣地,HotPDF Component 與 Delphi PDF Library 等原生元件在預設情況下即整合了強大的防禦性解析策略。它們實作了專門針對 Delphi 與 C++Builder 環境設計的嚴格邊界檢查、遞迴深度限制器以及記憶體洩漏預防機制。
無論您是選擇透過 Delphi 包裝函式庫呼叫 PDFium 進行彩現,還是利用 HotPDF 等原生元件建立與處理文件,您都能獲得企業級的安全性邊界,保護您的使用者與伺服器免受惡意負載的攻擊,而無需自行撰寫防禦性解析器。
注意:安全、經過模糊測試的解析能力支援我們的整個產品套件,包含 HotPDF Component、Delphi PDF Library 以及 PDFium Component。