如何检测已签名PDF文件在各次签名操作之间产生的内容变更
PDF签名间隔期修改行为检测实现方案
核心实现逻辑
PDF的数字签名会绑定签名触发时的文件修订状态,每次签名默认会将此前的修改作为增量区块追加到文件末尾,相邻两个签名之间的增量区块就包含了两次签名间隔期的所有修改内容,只需对比两个签名对应修订版本的注释集合差异,即可检测到签名人2新增注释的操作。
iText 实现步骤
- 调用
SignatureUtil的getSignatureNames()方法获取所有签名的名称列表,按签名时间升序排序得到签名序列 - 遍历签名序列,通过
extractRevision()方法分别提取相邻两个签名对应的修订版本字节流 - 分别解析两个修订版本的所有页面注释对象,优先比对PDF对象编号+生成号,其次比对注释内容、创建时间属性
- 两个版本的注释集合差集,就是两次签名间隔期间新增的注释内容
- 核心代码示例:
PdfDocument pdfDoc = new PdfDocument(new PdfReader(targetPdfPath)); SignatureUtil signUtil = new SignatureUtil(pdfDoc); List<String> sigList = signUtil.getSignatureNames(); // 按签名时间排序(如果需要) sigList.sort((a,b) -> signUtil.getSignature(a).getSignDate().compareTo(signUtil.getSignature(b).getSignDate())); for (int i = 1; i < sigList.size(); i++) { // 提取上一个签名的完整修订字节 byte[] prevRevision = signUtil.extractRevision(sigList.get(i-1)); // 提取当前签名的完整修订字节 byte[] currRevision = signUtil.extractRevision(sigList.get(i)); // 自行封装工具方法:从PDF字节流中提取所有注释对象 List<PdfAnnotation> prevAnnos = parseAllAnnotations(prevRevision); List<PdfAnnotation> currAnnos = parseAllAnnotations(currRevision); // 差集即为间隔期新增的注释 List<PdfAnnotation> addedAnnos = currAnnos.stream() .filter(anno -> !prevAnnos.contains(anno)) .toList(); }
PDFBox 实现步骤
- 调用
getSignatureDictionaries()方法获取所有签名字典,按签名时间升序排序 - 调用
getSignedContent()方法分别提取相邻两个签名对应的修订版本字节流 - 解析两个修订版本的页面
/Annots属性数组,比对注释对象差异即可 - 核心代码示例:
PDDocument document = PDDocument.load(new File(targetPdfPath)); List<PDSignature> sigList = document.getSignatureDictionaries(); sigList.sort((a,b) -> a.getSignDate().compareTo(b.getSignDate())); FileInputStream fis = new FileInputStream(targetPdfPath); for (int i = 1; i < sigList.size(); i++) { byte[] prevRevision = sigList.get(i-1).getSignedContent(fis); byte[] currRevision = sigList.get(i).getSignedContent(fis); List<PDAnnotation> prevAnnos = parseAllAnnotations(prevRevision); List<PDAnnotation> currAnnos = parseAllAnnotations(currRevision); // 差集即为间隔期新增的注释 }
注意事项
- 若前序签名设置了允许添加注释的修改权限,该新增注释操作属于合规修改,若需要拦截此类操作,需在首次签名时设置修改权限为
不允许任何修改 - 比对注释时优先比对PDF对象的编号和生成号,避免出现内容相同但为新增对象的漏判情况
- 若文件不是按增量模式保存而是直接覆盖保存,会导致前序签名直接失效,可直接判定为文件被篡改
内容的提问来源于stack exchange,提问作者Asmaa Fathy
相关产品推荐
相关产品推荐

