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

Безопасность: шифрование, криптополитика и поверхность подписания

Модуль безопасности Core применяет 256-битное шифрование документов Advanced Encryption Standard (AES-256), проводит каждый выбор алгоритма через контракт криптополитики и предоставляет точки интеграции для службы управления ключами, управляемой на уровне развёртывания. Реальная защита документа зависит от работы с ключами, надёжности пароля, читающего приложения и среды развёртывания. Эта страница явно описывает эти границы.

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

У модуля безопасности три поверхности. Поверхность шифрования использует точку входа документа setEncryption() для настройки обработчика безопасности Standard на основе AES-256. Криптополитика использует CryptoPolicyInterface, чтобы определить, какие алгоритмы хеширования, подписи, шифрования и какую стойкость ключа разрешает развёртывание. Поверхность подписания упомянута здесь, но описана отдельно; см. Подписание.

Шифрование использует AES-256, как определено в ISO 32000-2:2020 §7.6. По умолчанию используется обработчик безопасности Standard V=5 / R=6 с фильтром шифрования AESV3. Ключ файла занимает 32 байта (256 бит), что соответствует Federal Information Processing Standards (FIPS) 197. Дополнительный путь добавляет аутентифицированное шифрование ISO/TS 32003:2023 V=6 / R=7 AES-256 in Galois/Counter Mode (AES-256-GCM). Подробная страница описывает оба пути: Шифрование.

Криптополитика — это предикат “запретить или разрешить”. Core обращается к CryptoPolicyInterface перед любым шагом подписания, шифрования или хеширования. Если политика не задана, Core разрешает любой алгоритм. Такое открытое значение по умолчанию подходит для разработки, но не для продакшена. В регулируемом развёртывании нужно задать явную политику. Contracts / Security Policy описывает поверхность контракта.

Флаги разрешений чаще всего становятся источником завышенных заявлений, поэтому эта страница говорит об этом прямо. Битовая маска разрешений хранится в зашифрованной записи /Perms и в значении /P. Ожидается, что читающее приложение, соответствующее стандарту, соблюдает эти ограничения. Криптография не обеспечивает соблюдение этих флагов. Обработчик, который игнорирует биты, всё равно может читать, копировать или изменять содержимое после получения ключа расшифровки. Указывайте это ограничение любой стороне, которая полагается на флаги разрешений.

Управление ключами и интеграция Public-Key Cryptography Standards #11 (PKCS#11) — это точки контракта. Core поставляет путь с локальным ключом. Объект-значение KeyMaterial оборачивает 256-битный ключ, проверяет длину и предотвращает раскрытие в строковом и отладочном выводе. Путь хранения ключей через hardware security module (HSM)/PKCS#11 — это возможность Enterprise, защищённая теми же контрактами; эта страница называет точку интеграции, но не описывает реализацию Enterprise.

ТипВидКлючевые элементыСтабильностьС версии
Document::setEncryption()метод (трейт HasSecurity)userPassword, ownerPassword, permissionsстабильно1.0.0
Document::useAesGcm()метод (трейт HasSecurity)?bool $enabled — дополнительный ISO/TS 32003 V=6/R=7стабильно2.18.0
Aes256Encryptorклассencrypt(), decrypt(), buildEncryptionDictionary(), verifyUserPassword(), verifyOwnerPassword(), validatePerms()стабильно1.0.0
Aes256GcmEncryptorклассencrypt(), decrypt(), encryptStream(), assertWithinSafetyBound(), invocationCount()стабильно2.18.0
KeyMaterialfinal readonly classgenerate(), exposeKey(), fingerprint()стабильно2.18.0
CryptoPolicyInterfaceинтерфейсisHashAlgorithmAllowed(), isSignatureAlgorithmAllowed(), isEncryptionAlgorithmAllowed(), isKeyStrengthAllowed(), getPreferredHashAlgorithm(), getName()стабильно1.9.0
Config::withCryptoPolicy()методCryptoPolicyInterface $policyстабильно1.9.0
CryptoCapabilitiesfinal classhasAesGcm(), detectFipsMode(), assertFipsAvailableForProfile()стабильно2.0.0
examples/22-protection.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../vendor/autoload.php';
use NextPDF\Core\Document;
$doc = Document::createStandalone();
$doc->setTitle('Encrypted Document — Restricted Permissions');
// Call setEncryption() BEFORE addPage().
// Permission bit 3 (value 4) = printing allowed; all other operations denied.
$doc->setEncryption(
userPassword: 'demo',
ownerPassword: 'admin',
permissions: 4,
);
$doc->addPage();
$doc->setFont('helvetica', 'B', 20);
$doc->cell(0, 14, 'Encrypted PDF Document', newLine: true);
$doc->save(__DIR__ . '/output/22-protection.pdf');

Пользовательский пароль открывает документ. Пароль владельца даёт полный доступ. Флаги разрешений ограничивают только читающее приложение, которое соблюдает стандарт.

examples/security/policy-gated-encryption.php
<?php
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use NextPDF\Contracts\CryptoPolicyInterface;
use NextPDF\Core\Document;
use Psr\Log\LoggerInterface;
final readonly class PolicyGatedEncryption
{
public function __construct(
private CryptoPolicyInterface $cryptoPolicy,
private LoggerInterface $logger,
) {}
/**
* Encrypt only when the active policy permits AES-256-CBC.
*
* @param non-empty-string $userPassword Opens the document.
* @param non-empty-string $ownerPassword Grants full access.
*/
public function protect(
Document $doc,
string $userPassword,
string $ownerPassword,
int $permissions,
): void {
if (!$this->cryptoPolicy->isEncryptionAlgorithmAllowed('aes-256-cbc')) {
$this->logger->error('Encryption refused by crypto policy', [
'policy' => $this->cryptoPolicy->getName(),
]);
throw new \RuntimeException('AES-256-CBC denied by the active crypto policy.');
}
$doc->setEncryption($userPassword, $ownerPassword, $permissions);
$this->logger->info('Document encrypted', [
'policy' => $this->cryptoPolicy->getName(),
'algorithm' => 'aes-256-cbc',
]);
}
}

Код обращается к политике перед шифрованием, записывает имя политики в журнал аудита и выбрасывает конкретное исключение, когда политика запрещает шифр.

  • Вызывайте setEncryption() до addPage(). Более поздний вызов не шифрует задним числом содержимое, которое модуль записи уже вывел.
  • Режим PDF/A и шифрование несовместимы. ISO 19005 запрещает ключ трейлера Encrypt во всех разновидностях PDF/A, поэтому setEncryption() и useAesGcm() выбрасывают исключение, когда активен менеджер PDF/A.
  • Внутри setEncryption() пустой пароль владельца заменяется на пользовательский пароль. Если документ использует один общий пароль, обладатель пользовательского пароля получает доступ уровня владельца.
  • Когда политика не внедрена, CryptoPolicyInterface разрешает любой алгоритм. Воспринимайте открытое значение по умолчанию как удобство для разработки и задавайте явную политику в любом регулируемом развёртывании.
  • Флаги разрешений носят рекомендательный характер для читающего приложения. Не описывайте их как контроль доступа, который враждебный обработчик не сможет обойти.

setEncryption() выполняет итеративную процедуру выведения ключа (Algorithm 2.B, revision 6) во время сборки документа. Затраты ограничены и постоянны для каждого документа; они не растут с числом страниц. Шифрование на уровне объектов выполняет одну операцию AES для каждого потока или строки. Дополнительный путь AES-256-GCM добавляет 28 байт накладных расходов на объект (12-байтовый вектор инициализации (IV) плюс 16-байтовый тег) и обрабатывает крупное содержимое блоками по 16 МиБ. Благодаря этому потоковый проход остаётся ниже задокументированного пика 64 МБ. Значение performance_budget в 1500 мс по времени и 64 МБ по пику определяется в основном отрисовкой документа, а не шифрованием.

Модель угроз описана явно. Криптополитика снижает риск понижения алгоритма, отклоняя слабые шифры, слабые хеши и короткие ключи до выполнения любой операции. Движок не подменяет запрошенный примитив более слабым, если тот недоступен; он выбрасывает исключение, чтобы оператор мог принять меры. KeyMaterial снижает риск раскрытия ключа через журналирование: его строковая и отладочная формы скрывают байты и раскрывают только необратимый отпечаток. Подделка шифротекста обнаруживается только на дополнительном пути AES-256-GCM: там проверяется тег аутентификации, и при несовпадении выбрасывается исключение вместо возврата открытого текста. Путь по умолчанию AES-256 Cipher Block Chaining (AES-256-CBC) обеспечивает только конфиденциальность и сам по себе не обнаруживает изменения. На пути GCM повторное использование IV предотвращается монотонным счётчиком плюс набором обнаружения коллизий по принципу эшелонированной защиты, что согласуется с требованием уникального IV в NIST SP 800-38D §8.

Границы описаны так же явно. Шифрование AES-256 применяется так, как определено в ISO 32000-2:2020 §7.6. Реальная защита зависит от надёжности пароля, управления ключами, среды развёртывания и читающего приложения. Читающие приложения, соответствующие стандарту, соблюдают флаги разрешений, но криптография их не обеспечивает. Зонд режима FIPS сообщает, загрузила ли сборка OpenSSL на хосте провайдер FIPS. Библиотека работает в FIPS-совместимом режиме, когда хост предоставляет проверенный модуль; сама она не сертифицирует ни один модуль. NIST SP 800-57 Part 1 §4 относит срок жизни ключа и криптопериод к обязанностям развёртывания. Core предоставляет средства управления, а развёртывание задаёт политику ротации.

Поверхность шифрования не передаёт байты документа, включая любую содержащуюся в них персональную информацию (PII), за пределы хоста. Выведение ключа, шифрование и расшифровка выполняются внутри процесса. Дополнительный путь GCM индексирует набор обнаружения коллизий IV в памяти по необратимому отпечатку ключа, а не по байтам ключа. Модуль безопасности не записывает на диск ни пароль, ни значение ключа. Развёртывание, которое направляет ключи через внешнюю службу управления ключами, отвечает за резидентность этой службы.

Безопасная телеметрия и очистка журналов

Заголовок раздела «Безопасная телеметрия и очистка журналов»

KeyMaterial::__toString() и __debugInfo() возвращают скрытую заглушку, поэтому при случайной записи объекта ключа в журнал попадает отпечаток, а не байты ключа. Пароли, передаваемые в setEncryption(), несут атрибут #[\SensitiveParameter], который скрывает их в трассировке стека. Для аудита используйте имя политики из CryptoPolicyInterface::getName() и 8-символьный отпечаток ключа как идентификаторы криптографической операции. Записывайте в журнал эти значения, но никогда — ключ или пароль.

УгрозаМеры в CoreОстаточная граница
Понижение алгоритма / подмена слабым шифромКриптополитика; без молчаливого ослабления (выбрасывает UnsupportedAlgorithmException)Действует только при внедрённой политике
Раскрытие ключа через журналыKeyMaterial: сокрытие; #[\SensitiveParameter] на пароляхВызывающий код, передающий exposeKey() в логгер, сводит это на нет
Подделка шифротекстаПроверка тега GCM на дополнительном путиПуть CBC по умолчанию обеспечивает только конфиденциальность
Повторное использование IV (GCM)Монотонный счётчик плюс набор обнаружения коллизий; переполнение отклоняется
Обход флага разрешенийНет; флаги носят рекомендательный характерЧитающее приложение, не соответствующее стандарту, игнорирует флаги
Перебор слабого пароляSASLprep плюс итеративное выведение ключа повышают стоимостьСлабый пароль остаётся доминирующим риском

Core не является криптографическим модулем, прошедшим валидацию FIPS, и не сертифицирован по FIPS. CryptoCapabilities::detectFipsMode() — это best-effort зонд времени выполнения: он читает переопределение оператора, затем список провайдеров OpenSSL, затем устаревший вызов режима FIPS и сообщает: активен, отсутствует или неопределён. assertFipsAvailableForProfile() отказывает по принципу fail-closed, когда профиль FIPS выбран на хосте, который не может подтвердить провайдер FIPS. Библиотека работает в FIPS-совместимом режиме, когда она настроена на сборку OpenSSL хоста, загрузившую провайдер, прошедший валидацию FIPS. Проверенная и сертифицированная позиция FIPS относится к Enterprise; см. документацию Enterprise.

ЗаявлениеСтандартПунктПодтверждение
Путь GCM сохраняет уникальность каждого IV для вызова, что согласуется с требованием уникальности стандарта.NIST SP 800-38D§8.2.1
Core предоставляет средства управления сроком жизни ключа и криптопериодом; политику задаёт развёртывание.NIST SP 800-57 Часть 1, ред. 5§4
Файловый ключ AES составляет 256 бит, что соответствует длине ключа стандарта.FIPS 197§4.2.1
Генерация ключа на токене — это точка интеграции для внешнего хранилища ключей.OASIS PKCS#11 v3.1C_GenerateKey

ISO 32000-2:2020 §7.6 — нормативная основа для обработчика безопасности Standard. Его текст ограничен лицензией и здесь пересказан, но не цитируется; эта страница ссылается на пункт по номеру. Каждый пункт выше представляет пересказ цитируемого стандарта.

Core определяет и фиксирует контракт криптополитики, поставляет путь шифрования AES-256 и предоставляет поверхность с локальным ключом. Редакция Enterprise предоставляет путь хранения ключей через HSM/PKCS#11 и профиль криптополитики в режиме FIPS за тем же CryptoPolicyInterface. Поверхность контракта одинакова во всех редакциях; развёртывание подключает другую реализацию политики и бэкенд хранения ключей.

  • Security / Encryption — подробный справочник по AES-256 и AES-256-GCM.
  • Contracts / Security Policy — контракты криптополитики и политики ресурсов.
  • Security / Signing — PDF Advanced Electronic Signatures (PAdES), Cryptographic Message Syntax (CMS) и метки времени.
  • Audit — журналирование аудита по имени политики и операциям.
  • Conformance — взаимодействие PDF/A с шифрованием.