跳转到内容

安全性:加密、加密策略与签名接口

Core 安全模块会为文件应用 AES-256 加密,并通过加密策略合约(crypto-policy)把关每一次算法选择,同时提供部署环境连接密钥管理服务所需的集成点。有效的文件保护取决于密钥处理、密码强度、消费端阅读器以及部署环境;本页会逐项说明这些边界。

Terminal window
composer require nextpdf/core:^3

安全模块集成了三个接口。第一个是加密:文件上的 setEncryption() 入口会设置 AES-256 Standard 安全处理器。第二个是加密策略门控:CryptoPolicyInterface 决定部署环境允许哪些哈希、签名、加密算法与密钥强度。第三个是签名接口,本页仅引用而不展开说明;请参阅 签名 一节。

加密采用 ISO 32000-2:2020 §7.6 所定义的 AES-256。默认路径使用搭配 AESV3 加密过滤器的 V=5/R=6 Standard 安全处理器。文件密钥长度为 32 字节(256 位),与 FIPS 197 一致。可选路径会添加 ISO/TS 32003:2023 V=6/R=7 的 AES-256-GCM 认证加密。深入说明页同时记录了两者:加密 一节。

加密策略门控是一项允许或拒绝的判定机制。Core 会在任何签名、加密或哈希步骤之前先检查 CryptoPolicyInterface。如果未设置任何策略,Core 会允许所有算法;这是适合开发、但不适合上线的开放默认值。受监管的部署环境必须设置明确的策略。合约/安全政策 一节记录了这个合约接口。

权限标志是最容易被夸大的一点,因此本页会明确说明。权限位掩码会随加密后的 /Perms 项以及 /P 值一起传递。符合规范的阅读器应遵守这些限制。这些标志并非由密码学强制执行。一旦取得解密密钥,忽略这些位的处理器仍可读取、复制或修改内容。请向任何依赖权限标志的一方说明这一限制。

密钥管理与 PKCS#11 集成属于合约接口。Core 内置一条本地密钥路径。KeyMaterial 值对象会包装一把经过长度检查的 256 位密钥,并通过其字符串与调试表示形式降低泄露风险。HSM 与 PKCS#11 密钥托管路径是 Enterprise 功能,并受相同合约把关;本页仅点明这一集成点,不详述 Enterprise 实现。

类型种类主要成员稳定性起始版本
Document::setEncryption()方法(concern HasSecurityuserPassword, ownerPassword, permissions稳定1.0.0
Document::useAesGcm()方法(concern HasSecurity?bool $enabled — 可选的 ISO/TS 32003 V=6/R=7稳定2.18.0
Aes256Encryptorclassencrypt(), decrypt(), buildEncryptionDictionary(), verifyUserPassword(), verifyOwnerPassword(), validatePerms()稳定1.0.0
Aes256GcmEncryptorclassencrypt(), decrypt(), encryptStream(), assertWithinSafetyBound(), invocationCount()稳定2.18.0
KeyMaterialfinal readonly classgenerate(), exposeKey(), fingerprint()稳定2.18.0
CryptoPolicyInterfaceinterfaceisHashAlgorithmAllowed(), 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 在所有 PDF/A 变体下都禁止 Encrypt trailer 键,因此当 PDF/A 管理器启用时,setEncryption()useAesGcm() 会抛出异常。
  • setEncryption() 内部,空的所有者密码会回退为使用用户密码。只使用一组共享密码的文件,会让持有用户密码的人获得所有者级别的访问权。
  • CryptoPolicyInterface 在未注入任何策略时会允许所有算法。请将这个开放默认值视为开发便利,并在任何受监管的部署环境中设置明确的策略。
  • 权限标志对阅读器而言只是建议。请勿把它们描述为连恶意处理器都无法绕过的访问控制。

setEncryption() 会在构建文件时执行一段迭代式密钥派生过程(Algorithm 2.B,第 6 版)。这项成本有上限,且对每份文件固定,不会与页数成正比。逐对象加密会对每个流或字符串执行一次 AES 运算。可选的 AES-256-GCM 路径会为每个对象增加 28 字节开销(12 字节 IV 加上 16 字节标签),并以 16 MiB 分块流式处理大型内容。这能让流式处理过程保持在已记录的 64 MB 峰值以下。1500 ms 墙钟时间与 64 MB 峰值的 performance_budget 主要由文件绘制主导,而不是加密步骤。

威胁模型很明确。算法降级由加密策略门控缓解;它会在任何运算之前拒绝弱加密算法、弱哈希与短密钥。当请求的基元不存在时,引擎不会悄悄改用较弱的基元,而是抛出异常,让操作者采取行动。KeyMaterial 会缓解因日志记录而泄露密钥的风险:其字符串与调试形式会遮蔽字节,只暴露一个不可逆的指纹。密文篡改只有在可选的 AES-256-GCM 路径上才会被检测到;在该路径上会验证认证标签,不匹配时抛出异常,而不是返回明文。默认的 AES-256-CBC 路径仅提供机密性,本身并不检测内容是否被修改。GCM 路径上的 IV 重用由单调递增计数器和一个纵深防御碰撞集合来缓解,符合 NIST SP 800-38D §8 对 IV 唯一性的要求。

边界同样明确。AES-256 加密按照 ISO 32000-2:2020 §7.6 定义的方式应用。有效保护取决于密码强度、密钥管理、部署环境以及消费端阅读器。权限标志由符合规范的阅读器遵守,并非由密码学强制执行。FIPS 模式探测会报告主机的 OpenSSL 构建是否已加载 FIPS 提供者。当主机提供经验证的模块时,库会以兼容 FIPS 的模式运行,且库本身并不认证任何模块。NIST SP 800-57 Part 1 §4 将密钥生命周期与加密周期界定为部署环境的责任。Core 提供这些控制项,但轮换策略由部署环境设置。

加密接口不会把文件字节传输到主机之外。密钥派生、加密与解密都在进程内执行。可选的 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() 是尽力而为的运行时探测:它会先读取操作者覆盖值,接着读取 OpenSSL 提供者清单,再读取传统的 FIPS 模式调用,并报告为已启用、不存在或无法判定。当在无法证明具备 FIPS 提供者的主机上选择了 FIPS 配置文件时,assertFipsAvailableForProfile() 会按失败关闭(fail closed)处理。当库配置为对应一个已加载 FIPS 验证提供者的主机 OpenSSL 构建时,它会以兼容 FIPS 的模式运行。经验证、已认证的 FIPS 态势属于 Enterprise 范畴;请参阅 Enterprise 文档。

声明标准条款佐证
GCM 路径会保持每次调用的 IV 唯一,符合该标准的唯一性要求。NIST SP 800-38D(区块密码操作模式标准)§8.2.1
密钥生命周期与加密周期由部署环境负责,Core 为此提供控制项。NIST SP 800-57 Part 1 Rev. 5(密钥管理标准)§4
AES 文件密钥为 256 位,与该标准的密钥长度相符。FIPS 197§4.2.1
令牌驻留式密钥生成是外部密钥存储区的集成点。OASIS PKCS#11 v3.1(密码令牌接口标准)C_GenerateKey(密钥生成函数)

ISO 32000-2:2020 §7.6 是 Standard 安全处理器的规范依据。其文本受授权限制,此处一律改写,绝不引用原文;该条款仅以编号方式引述。上述每一点都改写自所引述的标准。

Core 定义并冻结加密策略合约、提供 AES-256 加密路径,并提供一个本地密钥接口。Enterprise 版在相同的 CryptoPolicyInterface 之下提供 HSM/PKCS#11 密钥托管路径,以及一个 FIPS 模式的加密策略配置文件。合约接口在各版本之间完全相同;差异在于部署环境注入的策略实现与密钥托管后端。