Перейти к содержимому

NextPDF Symfony: безопасность и эксплуатация

Помощники формирования ответа применяют фиксированный набор заголовков безопасности. Объект передачи данных (DTO) асинхронного сообщения дважды проверяет выходной путь. Цифровая подпись необязательна и в редакции Pro ограничена базовым профилем, описанным здесь.

NextPDF\Symfony\Http\PdfResponse применяет один и тот же набор заголовков к каждому формируемому ответу: встроенному, для скачивания и обоим потоковым вариантам. Константа в исходном коде задаёт ровно эти заголовки:

ЗаголовокЗначение
Cache-Controlprivate, max-age=0, must-revalidate
Pragmapublic
X-Content-Type-Optionsnosniff
X-Frame-OptionsDENY
Content-Security-Policydefault-src 'none'
X-Robots-Tagnoindex, nofollow
Referrer-Policyno-referrer

Для создаваемых документов эти заголовки снижают риск content-type sniffing, отображения во фреймах, индексации и утечки реферера. Буферизованные варианты также задают Content-Type: application/pdf и Content-Length. Потоковые варианты задают тип содержимого и намеренно не задают Content-Length.

Бандл фиксирует этот набор заголовков. Чтобы добавить или изменить заголовки, например задать более строгий Cache-Control для скачиваний с аутентификацией, измените возвращаемый объект Response в контроллере перед его возвратом.

PdfResponse формирует заголовок Content-Disposition с защитными мерами. PdfResponseTest проверяет это поведение:

  • Имя файла очищается: разделители пути и последовательности обхода каталогов удаляются, поэтому имя вида ../../../etc/passwd.pdf не может выйти за пределы каталога.
  • Расширение .pdf добавляется, если его нет; существующее расширение не дублируется, в том числе в верхнем регистре .PDF.
  • Двойные кавычки и обратные слеши экранируются в строковой форме с кавычками.
  • Имена файлов вне ASCII получают запасной вариант в ASCII и вариант filename*=UTF-8'' по RFC-5987 (Request for Comments 5987).
  • Пустое имя файла заменяется на document.pdf.

Если имя файла зависит от пользовательского ввода, передавайте его только после проверки авторизации на уровне приложения. Бандл выполняет очистку для безопасности заголовка, а не для контроля доступа.

NextPDF\Symfony\Message\GeneratePdfMessage проверяет выходной путь в своём конструкторе. NextPDF\Symfony\Message\GeneratePdfHandler повторно проверяет его во время выполнения перед записью. При создании отклоняются:

  • пустой путь или путь, содержащий нулевой байт;
  • схема stream-wrapper, например php://...;
  • сегмент обхода каталогов .. с разделителем / или \;
  • путь, не оканчивающийся на .pdf (без учёта регистра);
  • значение builderClass, не являющееся синтаксически корректным именем класса.

Вторая проверка в обработчике важна, поскольку сообщение может оставаться в очереди между отправкой и обработкой. Обработчик не доверяет пути из очереди и снова применяет проверку пути перед сохранением. Запускайте обработчики от имени учётной записи файловой системы с минимальными привилегиями и доступом, ограниченным целевым выходным каталогом.

GeneratePdfHandler разрешает построители через сервис-локатор PHP Standard Recommendation 11 (PSR-11) по ключу — имени класса — и отклоняет всё, что не реализует PdfBuilderInterface. Поскольку локатор предоставляет только зарегистрированные построители, контролируемое злоумышленником значение builderClass в подделанной полезной нагрузке транспорта не может создать экземпляр произвольного класса. Согласно PSR-11, если контейнер сообщает, что идентификатор отсутствует, попытка разрешить его завершается ошибкой, а не молча возвращает неожиданный объект (PSR-11 §1.1.2). Регистрируйте в локаторе только доверенные классы построителей.

Необязательная конфигурация цифровой подписи

Заголовок раздела «Необязательная конфигурация цифровой подписи»

Цифровая подпись не входит в основной бандл. Она активируется только при наличии nextpdf/premium (который устанавливает редакцию Pro), когда compiler pass обнаруживает классы подписи из Pro. Когда бандл и редакция Pro установлены, поддерживаемая и документированная конфигурация подписи — профиль базового уровня B-B.

Узел конфигурации signature.level принимает дополнительные строковые значения для совместимости схемы в рамках семейства конфигураций NextPDF. В этом бандле поставляется и поддерживается возможность подписи B-B. Документация NextPDF Premium описывает профили подписи помимо B-B, их требования и аспекты эксплуатации. Здесь они намеренно не описываются.

Эксплуатационные замечания для сценария подписи B-B:

  • Подписант регистрируется только тогда, когда signature.enabled имеет значение true и задан signature.certificate; в противном случае раздел неактивен.
  • Передавайте сертификат, закрытый ключ и пароль через секреты Symfony или переменные окружения. Никогда не добавляйте их в репозиторий.
  • Ограничьте права на чтение ключевого материала только учётной записью приложения.

Реестры шрифтов и изображений принимают необязательный Psr\Log\LoggerInterface, привязанный через nullOnInvalid(). При наличии он выступает как заменяемая зависимость в рамках контракта логгера PHP Standard Recommendation 3 (PSR-3) (PSR-3). Удаляйте данные, идентифицирующие пользователя, из любого контекста журнала, который вы добавляете при создании документов; бандл не записывает в журнал содержимое документов.

Контрольный список усиления защиты при эксплуатации

Заголовок раздела «Контрольный список усиления защиты при эксплуатации»
  • Сохраняйте фиксированные заголовки ответа; для скачиваний с аутентификацией добавляйте более строгое кэширование на уровне контроллера.
  • Авторизуйте запрос перед созданием или возвратом документа; бандл не выполняет контроль доступа.
  • Храните ключевой материал для подписи в секретах Symfony / переменных окружения с правами доступа к файлам по принципу минимальных привилегий.
  • Запускайте обработчики Messenger под учётной записью с минимальными привилегиями и правом записи только в выходной каталог.
  • Держите ext-mbstring и ext-zlib включёнными (иначе бандл сразу завершается с ошибкой).
  • Зафиксируйте в приложении одну мажорную версию nextpdf/core, чтобы версия движка была детерминированной между развёртываниями.

Каждая строка содержит нормативное утверждение с этой страницы и привязана к полному 64-символьному шестнадцатеричному reference_id из закрытого корпуса организации по разработке стандартов (SDO). Происхождение (манифест корпуса, транспорт извлечения) указано в _sidecars/rag-citations.yaml.

СпецификацияРазделидентификатор (reference_id)Утверждение
PSR-11psr_11_container#1.1.2.p5если has() возвращает false, то get() выбрасывает NotFoundException
PSR-3psr_3_logger#x3.p17Необязательный компонент логгера

Цифровая подпись доступна только при установленном nextpdf/premium (Pro); поставляемый профиль этого бандла — базовый B-B. Эта необязательная возможность Pro не требует изменений кода в описанном здесь бандле Core. См. </get-license/?intent=symfony-pro>.

  • /integrations/symfony/production-usage/ — безопасность обработчиков и потоковая передача.
  • /integrations/symfony/configuration/ — таблицы signature, tsa и service.
  • /integrations/symfony/troubleshooting/ — диагностика проблем с подписью и Messenger.
  • /integrations/symfony/integration/ — полный справочник по сквозной настройке.