疑难解答:加密与权限标志
范围与边界
标题为“范围与边界”的章节本页条目涵盖引擎通过 NextPDF\Exception\EncryptionException 与 NextPDF\Security\Exception\DecryptionFailedException 抛出的解密失败,以及 PDF 权限标志的边界。
先说明边界,这能避免最常见的误解:加密字典中的 PDF 权限标志只记录作者的意图。它们并不是由本库强制执行的访问控制机制。忽略这些标志的阅读器(reader)仍然可以打印、复制或修改内容。请将这些标志视为向配合的阅读器提出的请求,而非强制手段。
条目:加密操作失败
标题为“条目:加密操作失败”的章节- 症状。 抛出
EncryptionException,消息形式为Encryption operation "<op>" failed using algorithm "<algorithm>"。 - 可能原因。 密码运算无法执行,通常是因为 OpenSSL 扩展缺失或配置错误、密钥素材无效,或在加密边界处 IV 长度不正确。
- 证据/诊断。
getContext()会返回algorithm与operation。operation的值是encrypt、decrypt或key_derivation之一,可用于定位失败阶段。 - 解法。
- 确认已安装并加载 OpenSSL PHP 扩展。
- 读取
operation字段以定位失败阶段。 - 若为
key_derivation,请验证密码或密钥输入。 - 重新执行该调用。
- 相关。 异常参考。
条目:解密因结构性原因而失败
标题为“条目:解密因结构性原因而失败”的章节- 症状。 抛出
DecryptionFailedException,消息形式为Decryption failed for "<algorithm>": <reason>。 - 可能原因。 密文因非篡改原因而无法处理,例如密文被截断、缺少 IV,或在 API 边界处提供了错误的密钥。由于可供评估的素材不足,完整性检查并未执行。
- 证据/诊断。
getContext()会返回algorithm与reason。源码将DecryptionFailedException记载为区别于TamperedDataException:这个异常表示配置或传输错误,并非篡改迹象。不要单凭它就视为安全事件。 - 解法。
- 读取
reason以识别结构性缺陷,例如ciphertext shorter than IV+tag。 - 确认密文在传输时未遭截断。
- 确认在边界处提供的密钥正是文档加密时所用的密钥。
- 重新执行该调用。
- 读取
- 相关。 签名与时间戳失败。
条目:抛出「数据遭篡改」异常
标题为“条目:抛出「数据遭篡改」异常”的章节- 症状。 抛出
NextPDF\Security\Exception\TamperedDataException,而非DecryptionFailedException。 - 可能原因。 完整性检查已执行且未通过。这有别于结构性解密失败:当时有足够的素材可评估完整性,但完整性验证未通过。
- 证据/诊断。 对照源码中的这两个类:
DecryptionFailedException属于结构性问题,并非安全事件;TamperedDataException则表示内容经过验证后未通过。 - 解法。
- 将输入视为不可信;不要使用解密后的内容。
- 从可信来源重新获取该文档。
- 若改用已知良好的来源后失败仍然持续,请捕获
getContext()以供事件报告之用。
- 相关。 签名与时间戳失败。
条目:权限标志未能阻止下游操作
标题为“条目:权限标志未能阻止下游操作”的章节- 症状。 生成的文档已设定权限标志(例如禁止复制或打印),但阅读器仍然复制或打印了内容。
- 可能原因。 这是预期内的边界,而非缺陷。本库不会将传入核心加密字典构建器的权限整数作为强制手段应用。这些标志属于建议性元数据;不遵守它们的阅读器并不会被 NextPDF 阻挡。
- 证据/诊断。
src/Security/Encryption/EncryptionDictionaryBuilder.php声明了buildDict(int $permissions, string $fileId),其中参数记载为ignored; retained for forward compatibility。该方法开头即执行unset($permissions, $fileId)。由src/Inspect/PdfPermissions.php暴露的权限标志是只读的检查字段,而非强制执行层。 - 解法。
- 不要依赖权限标志来阻止打印、复制或修改。 生成器库无法强制执行这些标志。
- 在必须限制访问的场景下,请管控文件本身的分发,或在 PDF 之外应用访问控制系统。
- 只将
PdfPermissions用于报告既有文档所声明的标志,而非用来断言那些动作已被阻止。
- 相关。 签名与时间戳失败。
条目:PDF/A 下加密遭拒
标题为“条目:PDF/A 下加密遭拒”的章节- 症状。 当同一次构建同时启用 PDF/A 并请求加密时,抛出
NextPDF\Security\Exception\IncompatiblePdfAModeException。 - 可能原因。 PDF/A 配置文件禁止在尾部(trailer)中使用
Encrypt键。无论调用顺序如何,引擎都会拒绝这个组合。 - 证据/诊断。 请参阅 PDF/A 与 PDF/UA 条目 中引用的条款、
getContext()字段,以及失败路径测试。 - 解法。
- 决定这份文档需要的是归档一致性,还是加密。
- 移除你不需要的那项属性对应的调用。
- 重新执行该管线。
- 相关。 PDF/A 与 PDF/UA 验证。
边角案例与陷阱
标题为“边角案例与陷阱”的章节DecryptionFailedException与TamperedDataException代表不同含义:分别是结构性失败与完整性验证失败。请按类进行分支判断,而非按消息文本。- 核心加密字典构建器会忽略权限整数;如果某个构建依赖核心包提供权限强制执行,那就是基于误解。
PdfPermissions只在完整检查深度下,针对已加密文档才会被填充,且反映其声明的标志。字段有值并不代表该动作已被阻止。