Enterprise 版本
內容解除武裝與重建 — 深入參考
本頁是 NextPDF\Enterprise\Security\Cdr 模組的深入參考。此模組解除不受信任 PDF 的武裝,並從其安全物件重建出一份乾淨檔案。管線為:解析、准入控制、威脅偵測、過濾、參照清洗、重建。輸出是輸入的安全投影,絕非具證據效力的副本。若需工作流程指引,請先閱讀 CDR 能力頁面。
供應與授權
標題為「供應與授權」的區段此能力隨 NextPDF Enterprise(nextpdf/enterprise)出貨,並以 Enterprise 層級的授權封套啟用。未持有該權利的部署不會載入此能力的類別。比較各版本並取得授權。
公開 API 介面
標題為「公開 API 介面」的區段| 符號 | 參數 | 預設行為 | 回傳 | 拋出或失敗於 | 備註 |
|---|---|---|---|---|---|
CdrEngine::__construct | 無 | 建構內部偵測器與重建器 | CdrEngine | 未宣告任何拋出 | 無可注入的協作者 |
CdrEngine::sanitize | string $pdfData、?CdrPolicy $policy = null | 在 CdrPolicy::standard() 下執行完整管線 | CdrResult | 對惡意輸入不拋出;解析與准入失敗回傳被拒結果 | 結果會將拒絕與消毒明確區分回報 |
CdrPolicy::__construct | 七個選用具名參數,見程式碼區塊 | 空移除集合;allowUriActions 為 false;flattenIncrementalUpdates 為 true;限制 100000 個物件、256 MiB 解碼、10000 頁、1000.0 膨脹比 | CdrPolicy | 未宣告任何拋出 | final readonly;空的 removeThreatTypes 清單不會偵測到任何項目 |
CdrPolicy::standard | 無 | 舊版威脅集合;移除 URI 動作;預設限制 | self | 未宣告任何拋出 | 排除七個有損的 Strip* case |
CdrPolicy::paranoid | 無 | 舊版威脅集合搭配更嚴限制:50000 個物件、128 MiB、5000 頁、100.0 膨脹比 | self | 未宣告任何拋出 | 排除七個有損的 Strip* case |
CdrPolicy::permissive | 無 | 僅移除 JavaScript、LaunchAction、NamedJavaScript、SubmitForm、ImportData;保留 URI 動作 | self | 未宣告任何拋出 | 供受信任來源使用 |
CdrPolicy::allThreatTypes | 無 | 回傳每一個 ThreatType case,含有損的 Strip* case | list<ThreatType> | 未宣告任何拋出 | 明確的最大化剝除選用啟用 |
CdrPolicy::legacyThreatTypes | 無 | 回傳除七個 Strip* case 外的每一個 case | list<ThreatType> | 未宣告任何拋出 | standard() 與 paranoid() 的預設移除集合 |
CdrPolicy::shouldRemove | ThreatType $type | 針對 removeThreatTypes 的成員資格測試 | bool | 未宣告任何拋出 | 當 allowUriActions 為 true 時,對 UriAction 回傳 false |
ThreatDetector::detect | PdfReader $reader、CdrPolicy $policy | 掃描每個物件與 trailer catalog 以尋找政策所定的威脅類型 | list<DetectedThreat> | 不拋出;無法解析的物件成為 UnparseableObject 威脅 | catalog 掃描涵蓋 /Names/JavaScript 樹 |
CdrRebuilder::rebuild | PdfReader $reader、list<int> $safeObjNums、list<int> $removedObjNums、CdrPolicy $policy | 將安全物件序列化為單修訂版 %PDF-2.0 檔案 | string | 未宣告任何拋出;重讀或 /Length 驗證失敗的物件會被略過 | $policy 保留供未來序列化調整 |
DetectedThreat::__construct | ThreatType $type、int $objectNumber、string $description、string $location = '' | 不可變的發現值物件 | DetectedThreat | 未宣告任何拋出 | 四個屬性皆為 public readonly |
ThreatType | 字串支撐列舉 | 二十個 case:十三個舊版加七個選用啟用的 Strip* case | 不適用 | 不適用 | 見下方 case 清單 |
進入點簽章
標題為「進入點簽章」的區段final class CdrEngine{ public function __construct()
public function sanitize(string $pdfData, ?CdrPolicy $policy = null): CdrResult}final readonly class CdrPolicy{ public function __construct( public array $removeThreatTypes = [], public bool $allowUriActions = false, public bool $flattenIncrementalUpdates = true, public int $maxObjects = 100_000, public int $maxDecodedStreamBytes = 268_435_456, public int $maxPageCount = 10_000, public float $maxInflationRatio = 1000.0, )
public static function standard(): self
public static function paranoid(): self
public static function permissive(): self
public static function allThreatTypes(): array
public static function legacyThreatTypes(): array
public function shouldRemove(ThreatType $type): bool}final class ThreatDetector{ public function detect(PdfReader $reader, CdrPolicy $policy): array}final class CdrRebuilder{ public function rebuild(PdfReader $reader, array $safeObjNums, array $removedObjNums, CdrPolicy $policy): string}final readonly class DetectedThreat{ public function __construct( public ThreatType $type, public int $objectNumber, public string $description, public string $location = '', )}enum ThreatType: stringThreatType case 清單
標題為「ThreatType case 清單」的區段十三個舊版 case 構成預設移除集合。Strip* case 依設計即為有損,永不進入預設政策。
| Case | 支撐值 | 偵測面 |
|---|---|---|
ThreatType::JavaScript | javascript | 任何物件上的 /JS 鍵,或 /S /JavaScript 動作 |
ThreatType::AdditionalActions | additional-actions | 任何物件上的 /AA 字典 |
ThreatType::OpenAction | open-action | 任何物件上的 /OpenAction 鍵 |
ThreatType::LaunchAction | launch-action | /S /Launch 動作 |
ThreatType::RemoteGoTo | remote-goto | /S /GoToR 或 /S /GoToE 動作 |
ThreatType::SubmitForm | submit-form | /S /SubmitForm 動作 |
ThreatType::ImportData | import-data | /S /ImportData 動作 |
ThreatType::EmbeddedFiles | embedded-files | /EmbeddedFiles name tree 或 /EF 字典 |
ThreatType::RichMedia | rich-media | /Subtype /RichMedia |
ThreatType::NamedJavaScript | named-javascript | Catalog /Names/JavaScript name tree |
ThreatType::UriAction | uri-action | /S /URI 動作;當 allowUriActions 為 true 時抑制 |
ThreatType::Xfa | xfa | /XFA 鍵 |
ThreatType::UnparseableObject | unparseable-object | 任何解析失敗的物件或 catalog |
ThreatType::StripJavaScript | strip-javascript | 選用啟用的超集:/JS 鍵、/S /JavaScript,或 /Subtype /JavaScript |
ThreatType::StripEmbeddedFiles | strip-embedded-files | 選用啟用:/Type /EmbeddedFile、/Type /Filespec、/EmbeddedFiles,或 /EF |
ThreatType::StripFormFields | strip-form-fields | 選用啟用:/Subtype /Widget、/FT 鍵,或 /AcroForm 鍵 |
ThreatType::StripAnnotationsRich | strip-annotations-rich | 選用啟用的 subtype:Movie、Sound、FileAttachment、3D、RichMedia、Screen |
ThreatType::StripOcgNonDefault | strip-ocg-non-default | 選用啟用:帶有 /Usage 或 /Visibility 鍵的 /Type /OCG |
ThreatType::StripDigitalSignaturesAtRebuild | strip-digital-signatures-at-rebuild | 選用啟用:/Type /Sig、/FT /Sig、/DSS、/VRI,或 /ByteRange |
ThreatType::Strip3dAndRichMedia | strip-3d-and-rich-media | 選用啟用的 subtype:3D、U3D、PRC、RMF、RichMedia、Sound、Movie |
行為合約
標題為「行為合約」的區段CdrEngine::sanitize 執行六個有序階段,且對惡意輸入永不拋出。
- 解析。 解析失敗會回傳
admitted為 false 並帶有解析錯誤拒絕原因的結果。此情況下消毒輸出為空。 - 准入控制。 物件數、彙總解碼串流位元組數、每串流膨脹比與頁數,皆會對照政策限制檢查。超限文件會被拒絕,而非消毒。拒絕與消毒會明確區分回報。
- 偵測。
ThreatDetector::detect掃描每個物件與 trailer catalog 以尋找政策所定的威脅類型。無法解析的物件會記錄為ThreatType::UnparseableObject發現,而非略過。 - 過濾。 帶有發現的物件會排入移除佇列。文件 catalog 絕不會被整個物件移除。Catalog 層級的發現(
OpenAction、AdditionalActions、NamedJavaScript)改以鍵剝除方式修補。 - 參照清洗。 每個指向已移除物件的間接參照,在序列化期間都會被替換為
null。 - 重建。
CdrRebuilder::rebuild輸出一份單修訂版%PDF-2.0檔案,物件經重新編號、附帶經典交叉參照表與全新 trailer。安全串流位元組會逐位元組相同地複製。重建後的 catalog 會捨棄/OpenAction、/AA與/Names;/AA會從每個物件捨棄。
回傳的 CdrResult 揭露重建後的位元組、已移除威脅清單、兩個位元組大小、准入旗標與拒絕原因。若來源具有可解析的 /Root 而重建輸出遺失了它,引擎會拒絕該輸出,而非回傳結構損毀的檔案。這是一項故障關閉保證:admitted 為 true 即代表輸出仍帶有文件 catalog 參照。
增量更新絕不會留存:重建在每個政策下都精確序列化為單一修訂版,因此陰影式的後期修訂會因構造而被扁平化。原有數位簽章無法在重建後維持有效,因為位元組範圍不再與輸出相符。
架構紅線。 CDR 是安全投影層,而非保存層。其輸出不得用於法律證據保存、與原件的雜湊比對,或封存副本。
邊界情況與失效模式
標題為「邊界情況與失效模式」的區段null政策會解析為CdrPolicy::standard()。以預設空removeThreatTypes建構的政策不會偵測或移除任何項目。allowUriActions設為true會抑制UriAction移除,即使該 case 存在於removeThreatTypes中亦然。flattenIncrementalUpdates在本版本中為宣告式:重建在每個政策下都輸出單一修訂版,包括將該旗標設為false的permissive()。- 膨脹比檢查將原始串流長度為零者視為一,因此從零膨脹的串流仍受限。當未保留任何解碼形式時,原始串流長度會計入彙總預算。
- 頁數准入檢查為盡力而為:catalog 或 page-tree 讀取失敗本身不會拒絕該文件。物件數與解壓縮預算則始終強制執行。
- 原始串流長度與其整數
/Length條目不符的物件,會在重建時被略過(多語言檔防禦)。指向此類被略過物件的參照會保留其來源物件編號,且在輸出中可能無法解析。sanitize()會拒絕可偵測到的損毀結果(缺少/Root),但直接驅動低階CdrRebuilder::rebuild()的呼叫方,必須自行重新驗證輸出結構與參照完整性。 - 當來源 trailer 帶有
/ID時,重建後的 trailer 會帶有全新產生的隨機/ID,而非原件的。其他 trailer 條目,包括/Info,都不會沿用;重建後的 trailer 持有/Size、可解析時的/Root,以及重新產生的/ID。 - 解碼後的 name 與 key 位元組會以十六進位跳脫方式重新輸出分隔符、空白與不可列印位元組,使惡意 name 無法將字典語法注入輸出。
- 位於已知 name 值集合之外的字典鍵下的字串值,會保守地以字面字串輸出。
CdrPolicy::legacyThreatTypes()會將任何未來的列舉 case 視為預設移除,除非它被登記為Strip*case,因此新的有損 case 無法悄然進入預設政策。- CDR 不是密碼學模組。其唯一的隨機性使用是重新產生的 trailer
/ID。簽章驗證不在此範圍;見 簽章深入參考。
符合性
標題為「符合性」的區段| 主張 | 標準 | 條款 |
|---|---|---|
| 叫用 ECMAScript 動作會使 PDF 處理器執行內嵌的指令碼。 | ISO 32000-2 | §12.6.4.17 |
JavaScript name tree 中的文件層級指令碼會在文件開啟時全部執行。 | ISO 32000-2 | §12.6.4.17 |
Catalog name 字典可持有一個文件層級指令碼動作的 JavaScript name tree。 | ISO 32000-2 | §7.7.4 (Table 32) |
| launch 動作會啟動應用程式,或開啟或列印文件。 | ISO 32000-2 | §12.6.4.6 |
/AA additional-actions 字典會擴充註解、頁面、欄位與 catalog 上的觸發事件。 | ISO 32000-2 | §12.6.3 |
| 不受信任檔案匯入必須限制傳入檔案的存在、數量與內容。 | OWASP ASVS 5.0 | §5.2 |
| 系統應防止上傳檔案的不當執行並偵測危險內容。 | OWASP ASVS 5.0 | §5.3 |
所有條款皆為釋義;NextPDF 不重現規範性文字。NextPDF 不作任何認證主張。 CDR 在所配置政策下移除 ThreatType 所列舉的主動內容面;它是一項能力,而非經認證的消毒器。CDR 不是防毒掃描器,也不偵測惡意軟體特徵;它補足而非滿足諸如 OWASP ASVS 5.4.3 防毒掃描等控制項。經解除武裝的檔案對某個匯入管線是否可接受,仍屬營運者的風險決策。
開發備註
標題為「開發備註」的區段- 模組原始碼帶有
@since 1.9.0;本參考記錄的是nextpdf/enterprise3.1.0 出貨的介面。 - 一切皆在你的主機上行程內執行。消毒期間不會發生網路存取。
CdrPolicy與DetectedThreat皆為final readonly;要變更限制請建構一個新的政策實例。CdrEngine在內部建構其偵測器與重建器。ThreatDetector與CdrRebuilder仍可直接使用,供供應自有PdfReader的分階段管線。CdrRebuilder::rebuild的$policy參數目前為保留;原始碼記載它是為呼叫端相容性與未來的每政策序列化調整而保留。- 輸出為結構可重現,而非位元可重現:當來源帶有
/ID時,重新產生的/ID在每次執行時皆不同。 - 結果型別
CdrResult(sanitize()的回傳值)已於上方以行為方式涵蓋;其欄位為public readonly,並以hadThreats()與threatCount()作為便利方法。
另請參閱
標題為「另請參閱」的區段- 內容解除武裝與重建(CDR) — 含工作流程與政策指引的能力頁面。
- 安全 — 深入參考
- 驗證 — 深入參考
- 鑑識 — 深入參考
發佈邊界
標題為「發佈邊界」的區段本頁僅記錄外部可觀察的行為與所支援的公開 API 介面。內部命名空間路徑、輔助類別、機制表、運維手冊檔名與工單前綴皆不在範圍內。