Làm sạch các tệp PDF không tin cậy: content disarm và reconstruction
Spec: ISO 32000-2, §12.6.4ISO 32000-2 §12.6.4
Tổng quan nhanh
Phần tiêu đề “Tổng quan nhanh”Một tệp PDF đến từ thế giới bên ngoài là mã nhiều ngang với là một tài liệu. Nó có thể mang JavaScript, một Launch action, một tệp thực thi được nhúng, và một cấu trúc được chế tác để làm vấp một bộ parse. Content Disarm & Reconstruction (CDR) coi tệp đó là không tin cậy, chỉ giữ lại những gì an toàn, và xây lại một tệp PDF sạch từ các phần sống sót.
Trang này giải thích cách CdrEngine của NextPDF Enterprise làm điều đó — và một điều
trung thực mà mọi nhà cung cấp CDR nên nói thẳng ra: tệp được xây lại là một security
projection của bản gốc, chứ không phải một bản sao trung thành với nó.
Vì sao điều này quan trọng
Phần tiêu đề “Vì sao điều này quan trọng”Các phần nguy hiểm của một tệp PDF không hề kỳ lạ. Chúng là các tính năng tiêu chuẩn. Đặc tả định nghĩa cả một danh mục các action — điều gì xảy ra khi một tài liệu mở ra, khi một trang được hiển thị, khi một trường thay đổi — và danh mục đó bao gồm JavaScript và Launch action (Spec: ISO 32000-2, §12.6.4ISO 32000-2 §12.6.4). Một trình đọc tôn trọng định dạng sẽ vui vẻ chạy chúng. Đó là điểm tựa của kẻ tấn công: một tệp vừa hoàn toàn hợp lệ vừa hoàn toàn độc hại cùng một lúc.
Lọc theo phần mở rộng tệp chẳng làm được gì ở đây. Mối đe dọa nằm bên trong một tệp PDF đúng định dạng, nên phòng thủ thực sự duy nhất là mở nó ra, hiểu nó, và tước bỏ bộ máy chủ động trước khi nó từng chạm tới một bộ render. Đây là tư thế xác-thực-đầu-vào mà chỉ dẫn về file-upload và input-validation của OWASP mô tả: không bao giờ tin các byte, và ưu tiên xây lại một hiện-vật biết-là-tốt hơn là quét một tệp thù địch để tìm các chữ ký biết-là-xấu.
Tóm tắt ngắn gọn
Phần tiêu đề “Tóm tắt ngắn gọn”- CDR giả định đầu vào là thù địch và tạo ra một tệp mới thay vì vá tệp cũ.
CdrEngine::sanitize()chạy sáu pha: parse, admission control, threat detection, filter, reference scrub, rebuild.- Nó trả về một
CdrResultcho bạn biết cái gì đã bị loại bỏ, liệu tài liệu có thậm chí được nạp hay không, và — nếu không — vì sao nó bị từ chối. - Đầu ra là một security projection. Nó dứt khoát không phải một bản sao làm bằng chứng, một hash khớp, hay một hiện-vật lưu trữ. Đó là một hợp đồng, không phải một lời cảnh báo nhỏ.
- Đây chỉ có ở Enterprise. NextPDF core không thực hiện CDR.
NextPDF tiếp cận điều này như thế nào
Phần tiêu đề “NextPDF tiếp cận điều này như thế nào”Tài liệu của chính engine nêu ra lằn ranh đỏ trong thiết kế bằng ba từ:
Security Projection Layer. sanitize() là một phép biến đổi phá hủy, không-thể-đảo-
ngược. Nó được phép vứt các byte đi. Cái nó không được phép làm là giả vờ kết quả là cùng
một tài liệu.
Đường ống được sắp xếp có chủ ý. Mỗi pha thu hẹp sự tin cậy trước khi pha kế tiếp tác động lên nó.
- ParsePdfReader builds the object graph from the raw bytes. A parse failure is a rejection, not a best-effort guess.
- Admission controlResource limits are checked first — object count, page count, decoded-stream size, per-stream inflation ratio. Over-budget input is rejected, never sanitised.
- DetectThreatDetector walks the graph and records each dangerous feature as a DetectedThreat with its object number and type.
- FilterObjects are partitioned into safe and removed. Catalog-level keys are stripped in place so the document catalog itself survives.
- Reference scrubPointers to removed objects are cleaned so the rebuilt file has no dangling references.
- RebuildCdrRebuilder serialises only the safe objects into a new PDF. The output is fresh structure, not an edited original.
Nạp trước khi tước. Trước khi một mối đe dọa duy nhất được loại bỏ, engine
hỏi liệu tài liệu có thậm chí đáng để xử lý hay không. CdrPolicy mang theo các
giới hạn — maxObjects, maxPageCount, maxDecodedStreamBytes, và một
maxInflationRatio phòng thủ chống các quả bom giải-nén. Một tài liệu
vượt qua chúng bị từ chối, và CdrResult nói rõ vậy với
admitted: false và một rejectionReason. Phân biệt này có tính trọng yếu:
“chúng tôi đã làm sạch nó” và “chúng tôi đã từ chối nó” là những kết cục khác nhau, và
kiểu result giữ chúng tách biệt để báo cáo lỗi của bạn cũng có thể làm vậy.
Các mối đe dọa được nêu tên, không phải đoán. ThreatDetector::detect() ánh xạ mỗi
cấu trúc nguy hiểm tới một ThreatType — JavaScript, LaunchAction,
OpenAction, AdditionalActions, RemoteGoTo, SubmitForm, ImportData,
EmbeddedFiles, RichMedia, NamedJavaScript, và nhiều hơn — mỗi cái gắn với một
tính năng PDF cụ thể. Một đối tượng hoàn toàn không thể parse được trở thành kiểu đe dọa
của riêng nó, UnparseableObject, vì một đối tượng mà bộ làm sạch không thể đọc là một
đối tượng nó không thể bảo lãnh. Mỗi phát hiện là một DetectedThreat mang theo
số đối tượng phạm lỗi, nên việc loại bỏ là chính xác.
Loại bỏ bảo vệ tài liệu, không chỉ payload. Một số khóa nguy hiểm
sống trên document catalog (Root) — một /OpenAction kích hoạt khi mở, chẳng hạn.
Loại bỏ cả đối tượng Root để giết một khóa sẽ phá hủy catalog và lặng lẽ làm hỏng tệp.
Engine xử lý những cái này như các lần tước-khóa-tại-chỗ trên catalog để thay thế, và
như một bộ canh giữ fail-closed nó từ chối phát ra một tài liệu được xây lại đã mất
/Root của nó hoàn toàn. Một bộ làm sạch tạo ra một tệp hỏng về mặt cấu trúc trong khi
báo cáo thành công đúng là kiểu thất bại mà bộ canh giữ này tồn tại để ngăn chặn.
Ví dụ thực tế
Phần tiêu đề “Ví dụ thực tế”Hình mẫu bên dưới là điểm vào thực. Bạn trao cho engine các byte thô và một policy; bạn
nhận lại một CdrResult trung thực về những gì đã xảy ra.
<?php
declare(strict_types=1);
use NextPDF\Enterprise\Security\Cdr\CdrEngine;use NextPDF\Enterprise\Security\Cdr\CdrPolicy;
$engine = new CdrEngine();
// Standard policy removes the known active threats — JavaScript, Launch// actions, remote go-to, form submit/import, and the rest — while leaving// the lossy opt-in "Strip*" cases off by default.$result = $engine->sanitize($untrustedPdfBytes, CdrPolicy::standard());
if (!$result->admitted) { // Rejected by admission control (e.g. object/page limit, zip bomb). // This is NOT a sanitised document. Do not serve it; report the reason. throw new \RuntimeException($result->rejectionReason);}
if ($result->hadThreats()) { // The disarmed bytes are safe to render. Each removed threat carries its // type and object number for your audit log — never silently. foreach ($result->removedThreats as $threat) { error_log(\sprintf( 'CDR removed %s in object %d', $threat->type->value, $threat->objectNumber, )); }}
$cleanBytes = $result->sanitizedPdf; // The security projection. Not the original.Không có đường đi nào mà đoạn mã này lặng lẽ trả lại một tệp vẫn-còn-nguy-hiểm. Hoặc tài
liệu được nạp và được tước, hoặc nó bị từ chối với một lý do được nêu. Danh sách
removedThreats nghĩa là việc tước là kiểm-toán-được, không phải phép thuật.
Hiểu lầm thường gặp
Phần tiêu đề “Hiểu lầm thường gặp”“CDR chỉ là che mật với vài bước thêm thắt.”
Không phải, và đánh đồng hai cái là nguy hiểm. Che mật loại bỏ thông tin — các tên, các số tài khoản, nội dung mà một con người không được phép thấy. CDR loại bỏ năng lực — JavaScript, Launch action, payload được nhúng mà một máy không được phép chạy. Chúng có những tiêu chí thành công đối ngược nhau. Một lần che mật đúng khi nội dung nhạy cảm biến mất và phần còn lại được giữ y nguyên. Một lần tước đúng khi mối đe dọa biến mất, và nó hoàn toàn sẵn lòng thay đổi cấu trúc lành tính để đạt tới đó. Hãy dùng công cụ khớp với ý định của bạn; đừng với lấy một cái rồi mong đợi các bảo đảm của cái kia.
Một hiểu lầm thứ hai là một lần xây lại sạch chứng minh bản gốc đã sạch. Nó chẳng chứng minh gì về bản gốc. Nó chỉ chứng minh rằng đầu ra không chứa mối đe dọa nào được phát hiện. Đầu vào có thể đã là một vũ khí; việc của CDR là bảo đảm cái bạn chuyển tiếp xuống hạ nguồn thì không.
Giới hạn và ranh giới
Phần tiêu đề “Giới hạn và ranh giới”Đây là phần các tờ rơi bỏ qua, nên chúng ta sẽ nói thẳng.
- Đầu ra là một security projection, không phải một bản sao làm bằng chứng. Mã nguồn
CdrEnginemang điều này như một lằn ranh đỏ kiến trúc. Tệp PDF đã được làm sạch không được dùng cho việc bảo toàn bằng chứng pháp lý, cho việc so sánh hash với bản gốc, hay làm một bản sao lưu trữ. Phép biến đổi là phá hủy và không-thể-đảo-ngược theo thiết kế. - Phát hiện có phạm vi. CDR loại bỏ các mối đe dọa nó biết cách nêu tên. Nó là một tầng mạnh, kiểm-toán-được trong một ngăn xếp phòng-thủ-theo-chiều-sâu — không phải một bảo đảm rằng một tệp không có mọi kỹ thuật tương lai có thể có. Hãy giữ nó phía sau cùng việc xác thực upload, kiểm tra content-type, và xử lý quyền-tối-thiểu mà chỉ dẫn file-upload của OWASP mô tả.
- Một số policy cố ý gây mất mát. Các trường hợp
Strip*opt-in loại bỏ các embedded file, chữ ký, trường form, layer, và 3D media. Những cái đó mạnh mẽ và chúng sẽ xóa nội dung hợp lệ — chẳng hạn một payload hóa đơn ZUGFeRD/Factur-X. Chúng tắt theo mặc định đúng vì lý do đó. Hãy bật chúng lên một cách hiểu biết. - Chữ ký không sống sót qua một lần xây lại. Tái dựng tệp thay đổi các byte của nó, nên bất kỳ chữ ký số gốc nào không còn khớp với dải byte của nó. Một tài liệu đã được tước là chưa-ký xét theo nguồn. Nếu bạn cần một hiện-vật đã ký, hãy ký đầu ra sạch như một hành động mới.
| Edition | Availability |
|---|---|
| Core | Not available. NextPDF core does not perform CDR. It parses, renders, and writes PDFs; it does not threat-detect or rebuild untrusted input. |
| Pro | Not available in the Pro edition. |
| Enterprise | Available via |
Tài liệu liên quan
Phần tiêu đề “Tài liệu liên quan”- How PDF encryption really works — nửa kia của việc xử lý các tệp PDF nhạy cảm: bảo vệ nội dung so với loại bỏ năng lực.
- Errors as a feature — triết lý fail-closed
mà các lần từ chối từ admission-control của CDR và bộ canh giữ
/Rootthể hiện. - An API that refuses to guess — vì sao một kiểu result phân biệt đã làm sạch với đã từ chối hơn hẳn một nỗ-lực-tốt-nhất lặng lẽ.
Bảng thuật ngữ
Phần tiêu đề “Bảng thuật ngữ”- CDR (Content Disarm & Reconstruction) — một chiến lược làm sạch parse một tệp không tin cậy, loại bỏ các thành phần chủ động hoặc nguy hiểm, và xây lại một tệp sạch từ phần còn lại an toàn, thay vì quét để tìm các chữ ký biết-là-xấu.
- Security projection — một đầu ra đã được làm sạch giữ lại đủ của nguồn để hữu dụng trong khi bảo đảm loại bỏ các mối đe dọa. Nó cố ý không trung-thành-từng-byte và không phù hợp làm bằng chứng, để hash, hay lưu trữ.
- Admission control — cổng tiền-làm-sạch từ chối các tài liệu vượt quá các giới hạn tài nguyên (số đối tượng, số trang, kích thước decoded-stream, tỷ lệ inflation) trước khi bất kỳ công việc tước nào bắt đầu.
- Action — một cấu trúc PDF làm cho một thứ gì đó xảy ra trên một kích hoạt chẳng hạn document-open hay một thay đổi trường; danh mục kiểu-action (Spec: ISO 32000-2, §12.6.4ISO 32000-2 §12.6.4) bao gồm JavaScript và Launch action, bề mặt đe dọa CDR điển hình.
- Dangling reference — một con trỏ tới một đối tượng không còn tồn tại sau khi lọc. Pha reference-scrub loại bỏ những cái này để tệp được xây lại vẫn nhất quán về mặt cấu trúc.