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

Contracts / Политика безопасности

Домен security-policy определяет три контракта с моделью запрета по умолчанию: CryptoPolicyInterface контролирует выбор алгоритмов и ключей, HtmlSecurityPolicyInterface ограничивает набор возможностей Hypertext Markup Language (HTML), а ExternalResourcePolicyInterface управляет загрузкой удалённых ресурсов. Поскольку каждый из них — контракт, вы можете задать более строгую политику развёртывания без форка.

Окно терминала
composer require nextpdf/core:^3

CryptoPolicyInterface — криптографический шлюз. Core вызывает его перед любой операцией подписи, шифрования или хеширования. Проверка охватывает хеш, идентификатор объекта подписи (OID), шифр и стойкость ключа. Контракт также сообщает минимальный хеш и имя политики для журнала аудита. Используйте его для применения набора правил, например Federal Information Processing Standards (FIPS) 140-3 или eIDAS. Код подписи и шифрования при этом не меняется. Если политика не задана, разрешены все алгоритмы. В регулируемой среде необходимо задать явную политику.

HtmlSecurityPolicyInterface работает на уровне разбора HTML. Он срабатывает до передачи содержимого в любой модуль отрисовки. Он определяет, разрешены ли тег, атрибут, свойство Cascading Style Sheets (CSS) или схема uniform resource locator (URL). Он также ограничивает размер ввода и глубину вложенности. Он работает совместно с транспортными политиками отдельных модулей отрисовки (Chrome, Cloudflare, Gotenberg), которые задают ограничения размера и заголовки Content Security Policy (CSP). Политика HTML сокращает поверхность атаки на уровне разбора. Исключённый тег никогда не доходит до макета. Внедрённый элемент не может изменить вывод. Если политика не задана, по умолчанию разрешён полный набор возможностей.

ExternalResourcePolicyInterface решает, может ли конвейер HTML загрузить внешний шрифт, таблицу стилей или изображение. Он также задаёт ограничения для каждой загрузки. Его позиция по умолчанию — запрет всего. Все параметры отключены, пока вы их не включите. Контракт следует принципу наименьших привилегий. Недоверенный HTML может ссылаться на URL, подконтрольный злоумышленнику. Загрузки @font-face контролируются по схеме, размеру и количеству глифов. @import контролируется по схеме, глубине и суммарному размеру. background-image контролируется по списку схем и списку разрешённых доменов с точным совпадением. Размер data-URI (Uniform Resource Identifier) ограничивается. Контракт также контролирует внешние ссылки Scalable Vector Graphics (SVG). Контракт указывает, что в production их необходимо всегда запрещать. Они открывают путь к подделке запросов и внедрению скриптов. Неограниченная загрузка по URL — путь к подделке запросов на стороне сервера. Контроль доступа можно обойти изменением URL, как описано в Open Worldwide Application Security Project (OWASP) Top 10 2025. Получение внешних компонентов должно быть ограничено официальными источниками и безопасным транспортом.

ТипВидОсновные членыСтабильностьС версии
CryptoPolicyInterfaceинтерфейсisHashAlgorithmAllowed(), isSignatureAlgorithmAllowed(), isEncryptionAlgorithmAllowed(), isKeyStrengthAllowed(), getPreferredHashAlgorithm(), getName()стабильно1.9.0
HtmlSecurityPolicyInterfaceинтерфейсisTagAllowed(), isAttributeAllowed(), isCssPropertyAllowed(), isUrlSchemeAllowed(), getMaxInputSize(), getMaxNestingDepth(), getName()стабильно3.1.0
ExternalResourcePolicyInterfaceинтерфейсisFontFaceAllowed(), getAllowedFontSchemes(), getMaxFontFileSize(), getMaxFontGlyphs(), isImportAllowed(), getMaxImportDepth(), isBackgroundImageAllowed(), getAllowedImageDomains(), getMaxDataUrlSize(), isSvgExternalReferenceAllowed()стабильно4.0.0

ExternalResourcePolicyInterface возвращает типизированные ограничения: размеры positive-int, глубину импорта int<1, 100>, а также списки схем и доменов list<non-empty-string>. Реализация по умолчанию запрещает все возможности.

examples/contracts/security-policy-quickstart.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\HtmlSecurityPolicyInterface;
/**
* Decide whether a tag survives the policy.
*
* @param HtmlSecurityPolicyInterface $policy A core or custom policy.
*/
function tagSurvives(HtmlSecurityPolicyInterface $policy, string $tag): bool
{
return $policy->isTagAllowed($tag);
}

Функция зависит только от контракта. Контракту удовлетворяют как ограничительная политика, так и политика по умолчанию.

examples/contracts/security-policy-production.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\CryptoPolicyInterface;
use NextPDF\Contracts\ExternalResourcePolicyInterface;
use NextPDF\Contracts\HtmlSecurityPolicyInterface;
use Psr\Log\LoggerInterface;
final readonly class UntrustedHtmlGate
{
public function __construct(
private HtmlSecurityPolicyInterface $htmlPolicy,
private ExternalResourcePolicyInterface $resourcePolicy,
private CryptoPolicyInterface $cryptoPolicy,
private LoggerInterface $logger,
) {}
/**
* Reject input that exceeds the configured limits before rendering.
*
* @param string $html Untrusted HTML markup.
*/
public function assertAcceptable(string $html): void
{
$maxInput = $this->htmlPolicy->getMaxInputSize();
if ($maxInput > 0 && \strlen($html) > $maxInput) {
$this->logger->warning('HTML rejected: input over limit', [
'policy' => $this->htmlPolicy->getName(),
'limit' => $maxInput,
]);
throw new \LengthException('HTML input exceeds policy limit.');
}
if ($this->resourcePolicy->isSvgExternalReferenceAllowed()) {
$this->logger->error('Unsafe policy: SVG external references enabled.');
throw new \LogicException('SVG external references must be denied in production.');
}
}
}

Шлюз применяет ограничение размера ввода и отклоняет небезопасную политику ресурсов до запуска конвейера. Он записывает имя политики в журнал для аудита и выбрасывает конкретное исключение.

  • CryptoPolicyInterface разрешает все алгоритмы, если политика не задана. Разрешающее значение по умолчанию — удобство для разработки, а не позиция для production. В любом регулируемом развёртывании задавайте явную политику.
  • HtmlSecurityPolicyInterface::getMaxInputSize() возвращает 0 при отсутствии ограничения. Трактуйте 0 как “нет ограничения политики”, а не “отклонить всё”. Дополнительно применяйте ограничение на транспортном уровне.
  • ExternalResourcePolicyInterface по умолчанию запрещает всё. Включение @font-face или background-image без задания списка схем открывает поверхность атаки для подделки запросов; одновременно задавайте список разрешений.
  • Пустой список разрешённых доменов в getAllowedImageDomains() означает, что после включения фоновых изображений разрешены все домены. Пустой список не является правилом запрета; указывайте явные домены.
  • isSvgExternalReferenceAllowed() в production должен возвращать false. Контракт документирует это; политика, возвращающая true, — обнаруженная проблема, а не вариант конфигурации.

Проверка политики — это вызов предиката: O(1), без затрат, пропорциональных размеру ввода. Во время разбора политика опрашивается для каждого тега, каждого атрибута, каждого свойства CSS и каждого URL. Патологический документ увеличивает количество вызовов, но каждый вызов по-прежнему выполняется за постоянное время. performance_budget в 1500 ms по времени и 64 MB по пику определяется разбором и отрисовкой, а не вычислением политики. Ограничения размера ввода и глубины вложенности сдерживают собственные затраты парсера. Строгая политика улучшает производительность в худшем случае, отклоняя слишком большой или глубоко вложенный документ до построения макета.

Эти контракты образуют защитный периметр движка, поэтому модель угроз задана явно. CryptoPolicyInterface снижает риск понижения алгоритма, блокируя слабые хеши и короткие ключи перед любой операцией. HtmlSecurityPolicyInterface снижает риск межсайтового скриптинга, влияющего на вывод Portable Document Format (PDF), и внедрения содержимого, удаляя запрещённые теги, атрибуты и CSS на уровне разбора до запуска модуля отрисовки. ExternalResourcePolicyInterface снижает риск подделки запросов на стороне сервера, бомб распаковки и бомб суммарного размера, по умолчанию запрещая всё и ограничивая каждую загрузку по схеме, размеру, глубине и домену. Ограничения размера ввода, глубины вложенности, количества глифов шрифта и глубины импорта снижают риск исчерпания ресурсов. Поскольку каждая политика — контракт, вы можете усилить периметр без форка движка, а имя политики доступно для записи в журнал аудита. Считайте весь HTML, все URL, а также все байты шрифтов и изображений враждебными. Эта страница помечена export_control_class: legal-review-required, поскольку контракты управляют криптографической политикой; текст пересказывает все нормативные источники и не цитирует ни один из них.

УтверждениеСтандартПунктПодтверждение
Неограниченная обработка URL позволяет обходить контроль доступа изменением URL; политика внешних ресурсов снижает этот риск запретом всего по умолчанию и списком разрешённых доменов с точным совпадением.OWASP Top 10 2025A01
Получение внешних компонентов должно быть ограничено официальными источниками и безопасным транспортом; политика поддерживает это через списки разрешённых схем.OWASP Top 10 2025Цепочка поставок ПО

Оба пункта пересказывают рекомендации OWASP. Страница ссылается на материалы OWASP по пунктам; движок не воспроизводит их текст.

Core определяет и фиксирует три контракта политики. Он поставляется с разрешающими значениями по умолчанию для разработки и строгими значениями по умолчанию для политики ресурсов с запретом всего. В редакции Enterprise профиль FIPS 140-3 поставляется за CryptoPolicyInterface, поэтому регулируемое развёртывание получает проверенную политику выбора алгоритмов без изменения кода подписи или шифрования. Набор контрактов идентичен во всех редакциях. Разница заключается в реализации политики, которую вы внедряете.