Санация недоверенных PDF: обезвреживание и реконструкция содержимого
Spec: ISO 32000-2, §12.6.4ISO 32000-2 §12.6.4
PDF, приходящий из внешнего мира, — это код в той же мере, в какой документ. Он может нести JavaScript, действие Launch, встроенный исполняемый файл и структуру, сделанную так, чтобы сбить парсер. Обезвреживание и реконструкция содержимого (Content Disarm & Reconstruction, CDR) трактует такой файл как недоверенный, оставляет только то, что безопасно, и пересобирает чистый PDF из выживших.
На этой странице объясняется, как CdrEngine в NextPDF Enterprise это делает, —
и та единственная честная вещь, которую каждый поставщик CDR должен сказать
вслух: пересобранный файл — это проекция безопасности оригинала, а не его
верная копия.
Почему это важно
Заголовок раздела «Почему это важно»Опасные части PDF не экзотичны. Это стандартные возможности. Спецификация определяет целый каталог действий — что происходит, когда документ открывается, когда показывается страница, когда меняется поле, — и этот каталог включает действия JavaScript и Launch (Spec: ISO 32000-2, §12.6.4ISO 32000-2 §12.6.4). Программа просмотра, которая уважает формат, с радостью их выполнит. Это и есть опора атакующего: файл, одновременно совершенно корректный и совершенно вредоносный.
Фильтрация по расширению файла здесь не делает ничего. Угроза внутри правильно сформированного PDF, так что единственная настоящая защита — открыть его, понять его и снять активную машинерию, прежде чем она вообще достигнет средства отрисовки. Это та позиция проверки ввода, которую описывает руководство OWASP по загрузке файлов и проверке ввода: никогда не доверяйте байтам и предпочитайте пересборку известно-хорошего артефакта сканированию враждебного на известно-плохие сигнатуры.
Если коротко
Заголовок раздела «Если коротко»- CDR предполагает, что вход враждебен, и производит новый файл, а не латает старый.
CdrEngine::sanitize()выполняет шесть фаз: разбор, контроль допуска, обнаружение угроз, фильтрация, очистка ссылок, пересборка.- Он возвращает
CdrResult, который сообщает вам, что было удалено, был ли документ вообще допущен и — если нет — почему он был отклонён. - Вывод — это проекция безопасности. Это явно не доказательственная копия, не совпадение хеша и не архивный артефакт. Это контракт, а не оговорка.
- Это только Enterprise. Ядро NextPDF не выполняет CDR.
Как NextPDF подходит к этому
Заголовок раздела «Как NextPDF подходит к этому»Собственная документация движка формулирует проектную красную линию в трёх
словах: Security Projection Layer. sanitize() — это разрушающее, необратимое
преобразование. Ему разрешено выбрасывать байты. Чего ему не разрешено — это
притворяться, что результат — тот же документ.
Конвейер намеренно упорядочен. Каждая фаза сужает доверие, прежде чем следующая фаза на нём действует.
- 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.
Допуск перед обезвреживанием. Прежде чем удалена хоть одна угроза, движок
спрашивает, стоит ли документ вообще обрабатывать. CdrPolicy несёт пределы —
maxObjects, maxPageCount, maxDecodedStreamBytes и maxInflationRatio,
который защищает от бомб декомпрессии. Документ, который пробивает их насквозь,
отклоняется, и CdrResult говорит об этом с admitted: false и
rejectionReason. Это различие несущее: «мы его очистили» и «мы его отказали» —
разные исходы, и тип результата держит их порознь, чтобы и ваша отчётность об
ошибках могла так же.
Угрозы названы, а не угаданы. ThreatDetector::detect() сопоставляет каждую
опасную конструкцию ThreatType — JavaScript, LaunchAction, OpenAction,
AdditionalActions, RemoteGoTo, SubmitForm, ImportData, EmbeddedFiles,
RichMedia, NamedJavaScript и другим, — каждый привязан к конкретной
возможности PDF. Объект, который вообще нельзя разобрать, становится собственным
типом угрозы, UnparseableObject, потому что объект, который санитайзер не может
прочитать, — это объект, за который он не может поручиться. Каждая находка — это
DetectedThreat, несущий номер нарушающего объекта, так что удаление точно.
Удаление защищает документ, а не только нагрузку. Некоторые опасные ключи
живут на каталоге документа (Root) — /OpenAction, который срабатывает при
открытии, например. Удаление всего объекта Root, чтобы убить один ключ,
уничтожило бы каталог и по-тихому сломало бы файл. Движок обрабатывает их как
снятие ключей на месте на каталоге, а в качестве защиты со сбоем закрыто
отказывается выдавать пересобранный документ, который потерял свой /Root
вообще. Санитайзер, который производит структурно сломанный файл, отчитываясь об
успехе, — это ровно тот режим сбоя, для предотвращения которого существует эта
защита.
Практический пример
Заголовок раздела «Практический пример»Приведённая ниже форма — настоящая точка входа. Вы вручаете движку сырые байты и
политику; вы получаете обратно CdrResult, который честен о том, что произошло.
<?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.Нет пути, где этот код по-тихому возвращает всё ещё опасный файл. Либо документ
допущен и обезврежен, либо он отклонён с заявленной причиной. Список
removedThreats означает, что обезвреживание поддаётся аудиту, а не волшебно.
Распространённое заблуждение
Заголовок раздела «Распространённое заблуждение»«CDR — это просто редактирование с дополнительными шагами».
Это не так, и смешивание этих двух опасно. Редактирование удаляет информацию — имена, номера счетов, содержимое, которое человек не должен видеть. CDR удаляет возможность — JavaScript, действие Launch, встроенную нагрузку, которую машина не должна запускать. У них противоположные критерии успеха. Редактирование верно, когда конфиденциальное содержимое ушло, а остальное сохранено дословно. Обезвреживание верно, когда угроза ушла, и оно совершенно готово изменить безобидную структуру, чтобы этого достичь. Используйте инструмент, который соответствует вашему намерению; не тянитесь за одним, ожидая гарантий другого.
Второе заблуждение — что чистая пересборка доказывает, что оригинал был чист. Она не доказывает об оригинале ничего. Она доказывает лишь, что вывод не содержит обнаруженной угрозы. Вход мог быть оружием; задача CDR — убедиться, что то, что вы передаёте дальше по потоку, оружием не является.
Пределы и границы
Заголовок раздела «Пределы и границы»Это та часть, которую брошюры пропускают, так что мы скажем её прямо.
- Вывод — это проекция безопасности, а не доказательственная копия. Исходный
код
CdrEngineнесёт это как архитектурную красную линию. Санированный PDF не должен использоваться для сохранения юридических доказательств, для сравнения хеша с оригиналом или как архивная копия. Преобразование по своей природе разрушающее и необратимое. - У обнаружения есть область. CDR удаляет угрозы, которые умеет называть. Это сильный, поддающийся аудиту слой в стеке эшелонированной защиты — не гарантия, что файл свободен от всякой возможной будущей техники. Держите его за той же проверкой загрузки, проверками типа содержимого и обработкой с наименьшими привилегиями, которые описывает руководство OWASP по загрузке файлов.
- Некоторые политики намеренно с потерями. Включаемые случаи
Strip*удаляют встроенные файлы, подписи, поля форм, слои и 3D-медиа. Они мощны и будут удалять легитимное содержимое — скажем, нагрузку счёта ZUGFeRD/Factur-X. Они выключены по умолчанию ровно по этой причине. Включайте их осознанно. - Подписи не переживают пересборку. Реконструкция файла меняет его байты, так что любая исходная цифровая подпись больше не соответствует своему диапазону байтов. Обезвреженный документ не подписан в отношении источника. Если вам нужен подписанный артефакт, подпишите чистый вывод как новый акт.
| Edition | Availability |
|---|---|
| Core | Недоступно. Ядро NextPDF не выполняет CDR. Оно разбирает, отрисовывает и записывает PDF; оно не обнаруживает угрозы и не пересобирает недоверенный ввод. |
| Pro | Недоступно в издании Pro. |
| Enterprise | Доступно через |
Связанная документация
Заголовок раздела «Связанная документация»- Как на самом деле работает шифрование PDF — другая половина обращения с конфиденциальными PDF: защита содержимого против удаления возможности.
- Ошибки как функция — философия сбоя
закрыто, которую воплощают отклонения контроля допуска CDR и защита
/Root. - API, отказывающийся гадать — почему тип результата, который различает очищено и отклонено, лучше тихого подхода «как получится».
Глоссарий
Заголовок раздела «Глоссарий»- CDR (Content Disarm & Reconstruction) — стратегия санации, которая разбирает недоверенный файл, удаляет активные или опасные компоненты и пересобирает чистый файл из безопасного остатка, а не сканирует на известно-плохие сигнатуры.
- Проекция безопасности — санированный вывод, который сохраняет достаточно источника, чтобы быть полезным, гарантируя при этом удаление угроз. Он намеренно не верен по байтам и не пригоден для доказательств, хеширования или архивации.
- Контроль допуска — предсанационный шлюз, который отклоняет документы, превышающие пределы ресурсов (число объектов, число страниц, размер декодированного потока, коэффициент инфляции), прежде чем начнётся какая-либо работа по обезвреживанию.
- Действие — конструкция PDF, которая заставляет что-то произойти по триггеру, такому как открытие документа или изменение поля; каталог типов действий (Spec: ISO 32000-2, §12.6.4ISO 32000-2 §12.6.4) включает действия JavaScript и Launch, каноническую поверхность угроз CDR.
- Висячая ссылка — указатель на объект, который больше не существует после фильтрации. Фаза очистки ссылок удаляет их, чтобы пересобранный файл оставался структурно согласованным.