Skip to content

Лучшие практики безопасности

Это руководство предоставляет практические рекомендации по безопасности для развёртывания TCPDF-Next в продакшен-окружениях. Следование этим практикам гарантирует, что ваш конвейер генерации PDF соответствует корпоративным стандартам безопасности.

Валидация ввода (санитизация HTML перед writeHtml)

При генерации PDF из HTML, предоставленного пользователем, всегда санитизируйте ввод перед передачей в HTML-рендерер. HtmlRenderer TCPDF-Next парсит и рендерит HTML точно, что означает, что вредоносная разметка может быть использована, если не санитизирована.

php
use YeeeFang\TcpdfNext\Html\HtmlRenderer;

// DANGEROUS: Never pass raw user input directly
// $renderer->writeHtml($userInput);

// SAFE: Sanitize first with a dedicated library
$clean = \HTMLPurifier::getInstance()->purify($userInput);
$renderer->writeHtml($clean);

Ключевые правила:

  • Удалите теги <script>, <iframe>, <object>, <embed> и <link> перед рендерингом.
  • Удалите схемы URI javascript: и data: из атрибутов href и src.
  • Ограничьте разрешённые CSS-свойства теми, которые нужны для макета (без position: fixed, без url() в CSS-значениях).
  • Проверьте кодировку символов — убедитесь, что ввод является валидным UTF-8 перед передачей рендереру.

Управление сертификатами (безопасное хранение и ротация)

Иерархия хранения

МетодУровень безопасностиСлучай использования
Аппаратный модуль безопасности (HSM)НаивысшийПроизводственные среды, регулируемые отрасли
Облачный KMS (AWS KMS, Azure Key Vault, GCP KMS)ВысокийОблачные развёртывания
PKCS#12-файл с надёжной парольной фразойСреднийНебольшие развёртывания
PEM-файл (зашифрованный)Средне-низкийРазработка, тестирование
PEM-файл (незашифрованный)НаинизшийНикогда в продакшене

Политика ротации

  • Обновляйте сертификаты не менее чем за 30 дней до истечения срока.
  • Мониторьте истечение с автоматическими оповещениями на 30, 14, 7 и 1 день.
  • Немедленно отзывайте скомпрометированные сертификаты через выдающий CA.
  • Ведите подписанный журнал аудита всех операций жизненного цикла сертификатов.
php
use YeeeFang\TcpdfNext\Certificate\CertificateStore;

$store = new CertificateStore();
$store->loadFromDirectory('/etc/tcpdf-next/certs/', '*.pem');

$activeCert = $store->getActiveCertificate('document-signing');

if ($activeCert->getExpirationDate() < new \DateTimeImmutable('+30 days')) {
    $logger->warning('Signing certificate expires soon', [
        'subject' => $activeCert->getSubject(),
        'expires' => $activeCert->getExpirationDate()->format('Y-m-d'),
    ]);
}

DANGER

Никогда не храните приватные ключи в репозиториях исходного кода, незашифрованных файлах на общих файловых системах, столбцах базы данных без шифрования в покое или лог-файлах.

Обработка паролей (SASLprep и надёжные пароли)

При установке паролей шифрования PDF применяйте нормализацию Unicode через SASLprep (RFC 4013) для обеспечения согласованной обработки паролей на разных платформах:

php
// TCPDF-Next automatically applies SASLprep to passwords
$pdf->setEncryption()
    ->setAlgorithm(EncryptionAlgorithm::AES256)
    ->setUserPassword('pässwörd-with-ünïcöde')  // SASLprep normalized internally
    ->setOwnerPassword($strongOwnerPassword)
    ->apply();

Рекомендации по парольной политике:

  • Минимум 12 символов для пользовательских паролей, 20 символов для паролей владельца.
  • Используйте криптографически безопасный генератор случайных чисел для паролей владельца (random_bytes()).
  • Никогда не прописывайте пароли в исходном коде — загружайте из переменных окружения или менеджеров секретов.
  • Очищайте пароли из памяти после использования через sodium_memzero().

Предотвращение SSRF (валидация URL для изображений, TSA, OCSP)

TCPDF-Next блокирует SSRF по умолчанию, но необходимо настроить белые списки для легитимных внешних ресурсов:

php
use YeeeFang\TcpdfNext\Security\NetworkPolicy;

$networkPolicy = NetworkPolicy::create()
    ->denyPrivateNetworks()     // Block 10.x, 172.16.x, 192.168.x
    ->denyLoopback()            // Block 127.0.0.1
    ->denyLinkLocal()           // Block 169.254.x
    ->allowDomain('cdn.yourcompany.com')       // Images
    ->allowDomain('timestamp.digicert.com')    // TSA
    ->allowDomain('ocsp.digicert.com')         // OCSP
    ->setMaxRedirects(3)
    ->setRequestTimeout(10);

$pdf = PdfDocument::create()
    ->setNetworkPolicy($networkPolicy)
    ->build();

Чек-лист:

  • Проверяйте все URL перед загрузкой (схема, хост, порт).
  • Явно добавляйте в белый список домены TSA и OCSP-респондеров.
  • Блокируйте file://, gopher://, ftp:// и другие не-HTTP(S) схемы.
  • Логируйте все заблокированные запросы для мониторинга безопасности.

Валидация путей файлов (предотвращение обхода путей)

При приёме путей к файлам от пользователя (например, для файлов шрифтов, изображений или путей вывода):

php
use YeeeFang\TcpdfNext\Security\ResourcePolicy;

$resourcePolicy = ResourcePolicy::strict()
    ->allowLocalDirectory('/app/public/assets/')
    ->allowLocalDirectory('/app/storage/fonts/')
    ->denyAllRemote();

$pdf = PdfDocument::create()
    ->setResourcePolicy($resourcePolicy)
    ->build();

Правила:

  • Никогда не конкатенируйте пользовательский ввод напрямую в пути к файлам.
  • Преобразуйте пути в абсолютную каноническую форму и проверяйте относительно разрешённых каталогов.
  • Отклоняйте пути, содержащие .., нулевые байты или непечатаемые символы.
  • Используйте ResourcePolicy::strict() в продакшене — он запрещает весь доступ по умолчанию.

Безопасность развёртывания (Docker и права доступа к файлам)

Конфигурация Docker

dockerfile
FROM php:8.5-fpm-alpine

# Run as non-root user
RUN addgroup -S tcpdf && adduser -S tcpdf -G tcpdf
USER tcpdf

# Disable dangerous PHP functions
RUN echo "disable_functions = exec,passthru,shell_exec,system,proc_open,popen" \
    >> /usr/local/etc/php/conf.d/security.ini

# Read-only filesystem (mount writable volumes explicitly)
# docker run --read-only --tmpfs /tmp ...

Права доступа к файлам

bash
# Certificate directory: readable only by the web server user
chown -R www-data:www-data /etc/tcpdf-next/certs/
chmod 700 /etc/tcpdf-next/certs/
chmod 600 /etc/tcpdf-next/certs/*.p12
chmod 600 /etc/tcpdf-next/certs/*.pem

# Output directory: writable only by the web server user
chown -R www-data:www-data /var/lib/tcpdf-next/output/
chmod 700 /var/lib/tcpdf-next/output/

# Temporary directory: writable, not world-readable
chown -R www-data:www-data /tmp/tcpdf-next/
chmod 700 /tmp/tcpdf-next/

Content Security Policy для PDF, отображаемых в браузере

При доставке PDF inline в браузере установите соответствующие HTTP-заголовки для предотвращения атак встраивания:

php
return response($pdf->toString(), 200, [
    'Content-Type' => 'application/pdf',
    'Content-Disposition' => 'inline; filename="document.pdf"',
    'Content-Security-Policy' => "default-src 'none'; plugin-types application/pdf",
    'X-Content-Type-Options' => 'nosniff',
    'X-Frame-Options' => 'DENY',
    'Cache-Control' => 'no-store, no-cache, must-revalidate',
]);

Для PDF, содержащих конфиденциальные данные, предпочитайте Content-Disposition: attachment для принудительной загрузки вместо рендеринга в браузере.

Рекомендации по журналированию аудита

Настройте комплексное журналирование аудита для всех операций PDF, критичных с точки зрения безопасности:

php
use YeeeFang\TcpdfNext\Security\AuditLogger;

AuditLogger::configure([
    'channel' => 'tcpdf-security',
    'log_signing' => true,
    'log_encryption' => true,
    'log_validation' => true,
    'log_key_access' => true,
    'log_tsa_requests' => true,
    'log_resource_access' => true,   // Log image/font loading
    'log_blocked_requests' => true,  // Log SSRF blocks
    'redact_sensitive' => true,      // Redact passwords/keys from logs
]);

Мониторьте:

  • Неудачные попытки валидации подписей (возможная подделка документа).
  • Предупреждения об истечении срока сертификатов.
  • Сбои связи с TSA.
  • Необычный объём подписания (возможная компрометация ключа).
  • Заблокированные попытки SSRF (возможное зондирование атаки).
  • Загрузка ресурсов с неожиданных путей.

Принцип минимальных привилегий для разрешений PDF

При установке разрешений PDF-документа предоставляйте только минимально необходимый доступ:

php
use YeeeFang\TcpdfNext\Encryption\Permissions;

// RESTRICTIVE: Read-only document
$pdf->setEncryption()
    ->setPermissions(Permissions::ACCESSIBILITY)  // Only screen reader access
    ->setUserPassword('reader')
    ->setOwnerPassword($strongOwnerPassword)
    ->apply();

// MODERATE: Printable document
$pdf->setEncryption()
    ->setPermissions(
        Permissions::PRINT_HIGH_QUALITY
        | Permissions::ACCESSIBILITY
    )
    ->apply();

// AVOID: Granting all permissions defeats the purpose of encryption
// Permissions::ALL is available but should rarely be used

Рекомендации по разрешениям:

  • Никогда не предоставляйте MODIFY_CONTENTS, если получателю не нужно редактировать документ.
  • Всегда предоставляйте ACCESSIBILITY для совместимости с программами чтения с экрана (юридическое требование во многих юрисдикциях).
  • Используйте PRINT_HIGH_QUALITY вместо PRINT_LOW_QUALITY, если нет конкретной причины.
  • Документируйте обоснование каждого предоставленного разрешения в вашем коде.

Дополнительные материалы

Распространяется по лицензии LGPL-3.0-or-later.