如何在 PDF 中实现多次数字签名(iText 5 多重签名实践指南)

梦静吖_5567

梦静吖_5567

2026-09-09

912人浏览

原创

如何在 PDF 中实现多次数字签名(iText 5 多重签名实践指南)

本文详解 itext 5 中实现 pdf 多重签名的关键原理与实操要点,指出“仅显示最新签名”的根本原因在于签名后 pdf 被意外扁平化(flattening),导致历史签名字段丢失;并提供规避方案、代码优化建议及验证方法。

本文详解 itext 5 中实现 pdf 多重签名的关键原理与实操要点,指出“仅显示最新签名”的根本原因在于签名后 pdf 被意外扁平化(flattening),导致历史签名字段丢失;并提供规避方案、代码优化建议及验证方法。

在使用 iText 5 对 PDF 进行数字签名时,若希望同一份文档支持多个独立、可验证的签名(例如多方协同签署),必须严格遵循 PDF 签名的增量更新(incremental update)机制。你遇到的“第二次签名后仅显示最新签名”问题,并非代码逻辑错误,而是签名后的 PDF 文件被外部工具(如 LibreOffice Draw 7.5)进行了扁平化处理——该操作会将已签名的表单域(包括签名外观和签名字典)永久渲染为静态图形或删除签名结构,使原始签名元数据不可恢复。

✅ 正确实现多重签名的核心原则

  1. 禁止任何中间修改或“另存为”操作:每次签名必须基于上一次签名生成的 原始二进制流(即未被 PDF 查看器、编辑器或转换工具处理过的 .pdf 文件),且不能调用 stamper.setFormFlattening(true) 或类似破坏性操作。
  2. 使用增量保存(默认行为):iText 5 的 PdfStamper.createSignature(..., true) 中第三个参数 true 表示启用 append mode(追加模式),它会在文件末尾添加新签名数据,保留原有签名结构。这是多重签名的技术基础。
  3. 确保签名字段名称唯一:若需可视化多个签名域,每次调用 sap.setVisibleSignature(...) 时应指定不同的签名域名称(第三个参数 fieldName 不为空且不重复),例如 "signature1"、"signature2";否则后续签名会覆盖前一个字段定义。

? 示例:安全的多签名流程(伪代码 + 关键修正)

// 第一次签名(输入:原始 unsigned.pdf)
byte[] signed1 = signPdf(originalBytes, cert1, "signature1");

// 第二次签名(输入:必须是 signed1,而非其打开再保存后的副本!)
byte[] signed2 = signPdf(signed1, cert2, "signature2"); // ← 关键:直接复用上一轮输出字节数组

// 签名方法需支持复用已有签名PDF作为输入
private byte[] signPdf(byte[] inputPdf, X509Certificate cert, String fieldName) 
    throws IOException, DocumentException, GeneralSecurityException {
    PdfReader reader = new PdfReader(inputPdf); // ← 输入必须是纯二进制,无额外处理
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    // 注意:createSignature 第三个参数 'true' 启用增量写入
    PdfStamper stamper = PdfStamper.createSignature(reader, os, '\0', null, true);

    PdfSignatureAppearance sap = stamper.getSignatureAppearance();
    sap.setReason("Approved by Dept A");
    sap.setLocation("Beijing");
    // 指定唯一字段名,避免覆盖
    sap.setVisibleSignature(new Rectangle(100, 700, 250, 650), 1, fieldName);
    sap.setCertificationLevel(PdfSignatureAppearance.NOT_CERTIFIED);

    ExternalDigest digest = new BouncyCastleDigest();
    ExternalSignature signature = new CustomExternalSignature(/*...*/);
    MakeSignature.signDetached(sap, digest, signature, 
        new Certificate[]{cert}, null, null, null, 0, MakeSignature.CryptoStandard.CMS);

    stamper.close(); // 自动以增量方式写入
    reader.close();
    return os.toByteArray();
}

⚠️ 常见陷阱与验证建议

  • ❌ 错误做法:用 Acrobat / Foxit / LibreOffice 打开已签名 PDF → 点击“保存”或“另存为” → 再用此文件二次签名。这些操作极大概率触发扁平化。
  • ✅ 验证是否保留多重签名:
    • 使用 pdfinfo -meta signed.pdf 检查 /Signature 条目数量;
    • 用 Adobe Acrobat 打开 → “签名”面板 → 应列出全部签名项;
    • 编程验证:PdfReader.getAcroFields().getSignatureNames() 返回签名字段名列表。
  • 依赖项注意:确保 bouncycastle 版本兼容(推荐 bcprov-jdk15on-1.68+),并正确注册 Security.addProvider(new BouncyCastleProvider())。

? 总结

多重签名不是“重复调用签名方法”即可达成,而是一套对 PDF 文件生命周期的精细化管控:从原始文件出发,全程保持二进制完整性,仅通过 iText 的增量追加机制叠加签名数据。只要跳过任何中间渲染、导出或编辑环节,你的 PDF 就能自然承载无限次合规数字签名,并在标准阅读器中完整显示与验证。

极轻PDF
极轻PDF

专业的在线PDF工具,支持PDF编辑、转换、合并、压缩等多种功能,操作简单,处理高效,满足日常办公与学习中的PDF处理需求。

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

2026.09.30

20

10

LLVM RISC-V参数配置教程
LLVM RISC-V参数配置教程

本专题介绍LLVM对RISC-V基础ISA和扩展的支持方式,涵盖RV32、RV64、标准扩展、实验性扩展、厂商扩展、-menable-experimental-extensions和版本差异。

2026.09.30

40

14

LLVM IR中间表示入门指南
LLVM IR中间表示入门指南

本专题整理LLVM IR的核心概念,包括中间表示作用、模块结构、函数、基本块、SSA形式、类型系统和常见语法,帮助新手理解LLVM编译流程中的关键层。

2026.09.30

20

12

PDF转图片方法
PDF转图片方法

需要把 PDF 页面用于上传、预览、分享或图片归档时,PDF 转图片方法专题整理 JPG/PNG 格式选择、逐页导出、清晰度设置、批量下载和结果检查等流程,帮助用户稳定完成 PDF 图片化处理。

2026.09.30

20

26

PixTV AI视频生成与无限画布创作
PixTV AI视频生成与无限画布创作

PixTV专题整理AI视频与视觉内容创作相关功能使用教程,涵盖AI生图、视频生成、无限画布、多模型创作、素材管理、声音音乐及视频剪辑等功能,帮助用户快速掌握PixTV从创意到成片的完整制作方法。

2026.09.29

20

15

Buffalo框架数据库开发全教程
Buffalo框架数据库开发全教程

本专题围绕Buffalo框架数据库开发,讲解database.yml多环境配置、soda与fizz迁移生成回滚、模型结构体标签、增删改查与条件查询、一对多与多对多关联、数据校验、回调钩子、事务处理及原生SQL执行能力。

2026.09.23

240

15

Buffalo框架路由与请求处理实操指南
Buffalo框架路由与请求处理实操指南

本专题讲解Buffalo框架路由与请求处理机制,涵盖路由注册与分组、资源路由、Handler编写规范、Context上下文方法、参数绑定、中间件编写挂载、Session与Cookie读写、Flash消息及错误页面定制方法。

2026.09.23

140

15

Buffalo框架零基础入门教程
Buffalo框架零基础入门教程

本专题整理Buffalo框架入门内容,涵盖Go环境准备、buffalo CLI安装、新项目生成、目录结构说明、dev热加载启动、数据库连接配置与常见报错排查,帮助新手按约定优于配置的思路跑通第一个Buffalo框架应用。

2026.09.23

120

15

Conan创建软件包配方指南
Conan创建软件包配方指南

本专题介绍通过conanfile.py创建软件包的方法,讲解包名、版本、依赖和构建设置等基础信息,以及source、build、package、package_info等常用方法的作用及编写思路。

2026.09.22

60

12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.6万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 133.4万人学习