You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Python脚本检测PDF是否签名及提取公钥等签名信息?

检测PDF是否已签名并提取签名证书的Python方案

一、首选工具:pyhanko

pyhanko是专门针对PDF签名处理的Python库,能直接检测PDF签名、提取签名证书,无需手动解析复杂的PDF底层结构,非常适合新手使用,比PyPDF2(仅侧重文本提取)、cryptography(通用加密库)更贴合PDF签名场景。

1. 安装pyhanko

pip install pyhanko

2. 检测签名并提取证书的实现代码

以下脚本可完成PDF签名检测、证书信息查看,以及导出CER(证书文件)和PKCS7格式签名文件:

from pyhanko.pdf_utils.reader import PdfFileReader
from cryptography.hazmat.primitives.serialization import Encoding

def process_pdf_signatures(pdf_path):
    # 读取目标PDF文件
    with open(pdf_path, 'rb') as pdf_file:
        reader = PdfFileReader(pdf_file)
        
        # 快速判断是否存在签名
        if not reader.has_signatures():
            print("该PDF文件未包含任何签名")
            return
        
        # 遍历所有签名域并处理
        for sig_field_name in reader.list_signature_fields():
            sig_obj = reader.get_signature(sig_field_name)
            print(f"\n找到签名域:{sig_field_name}")
            
            # 提取并打印签名证书基本信息
            signing_cert = sig_obj.signing_cert
            if signing_cert:
                print("签名证书详情:")
                print(f"颁发主体:{signing_cert.subject.rfc4514_string()}")
                print(f"颁发机构:{signing_cert.issuer.rfc4514_string()}")
                
                # 导出证书为CER格式(PEM编码)
                cer_content = signing_cert.public_bytes(encoding=Encoding.PEM)
                cer_output_path = f"{sig_field_name}_cert.cer"
                with open(cer_output_path, 'wb') as cer_file:
                    cer_file.write(cer_content)
                print(f"证书已导出至:{cer_output_path}")
                
                # 导出签名为PKCS7格式
                pkcs7_content = sig_obj.pkcs7_signer_info
                if pkcs7_content:
                    pkcs7_output_path = f"{sig_field_name}_signature.p7s"
                    with open(pkcs7_output_path, 'wb') as pkcs7_file:
                        pkcs7_file.write(pkcs7_content)
                    print(f"PKCS7格式签名已导出至:{pkcs7_output_path}")

# 调用示例
process_pdf_signatures("your_target.pdf")

二、cryptography+PyPDF2的替代方案(不推荐新手)

如果一定要结合cryptography实现,需要手动解析PDF的签名字典结构,步骤繁琐,适合有PDF底层知识的开发者:

from PyPDF2 import PdfReader
from cryptography.hazmat.primitives.serialization import pkcs7, Encoding
from cryptography.hazmat.backends import default_backend

def extract_cert_with_cryptography(pdf_path):
    reader = PdfReader(pdf_path)
    # 检查是否存在表单域
    if '/AcroForm' not in reader.trailer['/Root'] or '/Fields' not in reader.trailer['/Root']['/AcroForm']:
        print("该PDF无签名域")
        return
    
    # 遍历所有表单字段,定位签名字段
    for field in reader.trailer['/Root']['/AcroForm']['/Fields']:
        if field.get('/FT') == '/Sig':
            sig_dict = field['/V']
            # 提取PKCS7格式的签名内容
            sig_contents = sig_dict['/Contents'].get_object()
            
            try:
                # 解析PKCS7数据获取证书
                certs = pkcs7.load_der_pkcs7_certificates(sig_contents, default_backend())
                for idx, cert in enumerate(certs):
                    cer_output_path = f"extracted_cert_{idx}.cer"
                    with open(cer_output_path, 'wb') as cer_file:
                        cer_file.write(cert.public_bytes(Encoding.PEM))
                    print(f"证书已导出至:{cer_output_path}")
            except Exception as e:
                print(f"解析证书失败:{str(e)}")

# 调用示例
extract_cert_with_cryptography("your_target.pdf")

注意:此方法需要处理PDF对象的底层编码和结构,容易出现解析异常,新手优先选择pyhanko方案。

三、其他简便检测方法

  • 命令行工具批量检测:使用pdftk命令行工具快速验证PDF是否有签名,适合批量处理场景:
    pdftk your_target.pdf dump_data | grep "Signature"
    
    若输出包含SignatureFieldName字段,则说明PDF已签名。
  • pypdfium2快速检测:通过pypdfium2库直接遍历PDF注释,快速判断是否存在签名:
    import pypdfium2 as pdfium
    
    def is_pdf_signed(pdf_path):
        pdf_doc = pdfium.PdfDocument(pdf_path)
        for page in pdf_doc:
            for annot in page.get_annotations():
                if annot.get_type() == pdfium.PDF_ANNOT_WIDGET and annot.get_field_type() == pdfium.PDF_FIELD_SIGNATURE:
                    return True
        return False
    
    print("PDF已签名" if is_pdf_signed("your_target.pdf") else "PDF未签名")
    

内容的提问来源于stack exchange,提问作者Raghu Varier

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 05:25:17