使用 Python 對(duì) PDF 文檔進(jìn)行數(shù)字簽名的方法
在合同、發(fā)票、報(bào)告等文件的流轉(zhuǎn)過(guò)程中,如何確認(rèn)文檔確實(shí)由某個(gè)簽署人發(fā)出,并且在簽署之后沒(méi)有被篡改,是一個(gè)經(jīng)常遇到的問(wèn)題。數(shù)字簽名正是為此設(shè)計(jì)的機(jī)制:它基于 PKI(公鑰基礎(chǔ)設(shè)施)技術(shù),把簽署人的身份與文檔內(nèi)容綁定在一起,一旦文檔被修改,簽名的校驗(yàn)就會(huì)失敗。
相比手動(dòng)在 Adobe Acrobat 等工具里逐份簽署,用程序批量處理簽名更適合需要自動(dòng)化的場(chǎng)景,例如系統(tǒng)自動(dòng)生成的合同、每日結(jié)算單、審批通過(guò)后自動(dòng)蓋章的流程文件等。本文將介紹如何用 Python 為 PDF 添加可見簽名、隱藏簽名和帶時(shí)間戳的簽名,并對(duì)已簽名文檔進(jìn)行驗(yàn)證。
數(shù)字簽名解決的問(wèn)題
用程序處理數(shù)字簽名,通常出于以下幾方面的考慮:
- 完整性校驗(yàn):簽名后文檔內(nèi)容一旦被改動(dòng),驗(yàn)證會(huì)立即失效,可以判斷文件是否被篡改。
- 身份認(rèn)證:簽名基于持有人的證書(PFX/PKCS#12 文件),能證明文檔由特定主體簽署。
- 批量自動(dòng)化:審批系統(tǒng)、結(jié)算系統(tǒng)可以在文件生成時(shí)自動(dòng)完成簽署,無(wú)需人工介入。
- 可長(zhǎng)期驗(yàn)證:結(jié)合時(shí)間戳服務(wù),即使簽署證書后續(xù)過(guò)期,也能證明簽署發(fā)生在證書有效期內(nèi)。
環(huán)境準(zhǔn)備
處理 PDF 簽名可以使用 Spire.PDF for Python,通過(guò) pip 安裝:
pip install Spire.Pdf
除了庫(kù)本身,還需要一個(gè)用于簽署的數(shù)字證書文件,通常是 .pfx(或 .p12)格式,并配有對(duì)應(yīng)的密碼。證書可以由 CA 機(jī)構(gòu)簽發(fā),也可以在測(cè)試階段使用自簽名證書。
添加可見的數(shù)字簽名
可見簽名會(huì)在頁(yè)面上繪制一個(gè)簽名框,顯示簽署人、原因、位置等信息,適合需要讓閱讀者直觀看到"已簽署"狀態(tài)的場(chǎng)景。
核心是 PdfOrdinarySignatureMaker 對(duì)象:它接收 PDF 文檔、證書文件路徑和證書密碼,負(fù)責(zé)完成簽署運(yùn)算。簽名的外觀則通過(guò) PdfSignatureAppearance 單獨(dú)配置。
from spire.pdf import *
# 加載 PDF 文檔
doc = PdfDocument()
doc.LoadFromFile("SampleB_1.pdf")
# 使用證書文件和密碼創(chuàng)建簽名生成器
signatureMaker = PdfOrdinarySignatureMaker(doc, "Jerry.pfx", "e-iceblue")
# 配置簽名的元數(shù)據(jù)
signature = signatureMaker.Signature
signature.Name = "Jerry"
signature.ContactInfo = "028-12345678"
signature.Location = "Chengdu"
signature.Reason = "文檔負(fù)責(zé)人簽署"
# 配置簽名外觀
appearance = PdfSignatureAppearance(signature)
appearance.NameLabel = "簽署人: "
appearance.ContactInfoLabel = "聯(lián)系方式: "
appearance.LocationLabel = "地點(diǎn): "
appearance.ReasonLabel = "原因: "
appearance.SignatureImage = PdfImage.FromFile("logo.png")
appearance.GraphicMode = GraphicMode.SignImageAndSignDetail
# 在第一頁(yè)指定位置繪制簽名框:x, y, 寬, 高
signatureMaker.MakeSignature("Signer:", doc.Pages.get_Item(0), 90.0, 550.0, 270.0, 90.0, appearance)
doc.SaveToFile("DigitalSignature.pdf")
doc.Dispose()
這里有幾個(gè)關(guān)鍵點(diǎn)值得說(shuō)明:
Signature屬性上設(shè)置的Name、Reason、Location等信息會(huì)被寫入簽名對(duì)象,PDF 閱讀器在展示簽名詳情時(shí)會(huì)讀取它們。GraphicMode決定簽名框里顯示什么內(nèi)容。SignImageAndSignDetail表示同時(shí)顯示圖片(如公司 Logo)和文字信息;也可以只顯示圖片或只顯示文字。MakeSignature的坐標(biāo)參數(shù)以點(diǎn)(point)為單位,原點(diǎn)在頁(yè)面左下角。最后四個(gè)數(shù)字分別對(duì)應(yīng)簽名框的左邊界、下邊界、寬度和高度。
添加隱藏簽名
有些場(chǎng)景并不希望在頁(yè)面上出現(xiàn)簽名框,只需要在文檔層面完成簽署以保證完整性即可。這時(shí)可以創(chuàng)建不帶外觀參數(shù)的隱藏簽名。
from spire.pdf import *
doc = PdfDocument()
doc.LoadFromFile("SampleB_1.pdf")
# 創(chuàng)建簽名生成器
signatureMaker = PdfOrdinarySignatureMaker(doc, "Jerry.pfx", "e-iceblue")
# 只傳簽名字段名稱,不設(shè)置外觀,即為隱藏簽名
signatureMaker.MakeSignature("signName")
doc.SaveToFile("AddInvisibleSignature.pdf")
doc.Dispose()
隱藏簽名同樣具備防篡改能力,閱讀器仍能在簽名面板中檢測(cè)到它,只是頁(yè)面上不顯示任何可見標(biāo)記。
添加帶時(shí)間戳的簽名
數(shù)字證書都有有效期。如果需要證明"簽署行為發(fā)生在證書仍然有效的時(shí)間點(diǎn)",就要引入可信時(shí)間戳服務(wù)(TSA)。Security_PdfSignature 提供了 ConfigureTimestamp 方法來(lái)指定 TSA 服務(wù)地址。
from spire.pdf import *
doc = PdfDocument()
doc.LoadFromFile("SampleB_1.pdf")
# 創(chuàng)建帶頁(yè)面引用的簽名對(duì)象
signature = Security_PdfSignature(doc, doc.Pages.get_Item(0), "Jerry.pfx", "e-iceblue", "signature")
# 設(shè)置簽名框的位置和大小
signature.Bounds = RectangleF(PointF(90.0, 550.0), SizeF(180.0, 90.0))
signature.NameLabel = "Digitally signed by: Jerry"
signature.Reason = "確保文檔真實(shí)性"
# 限制簽署后允許的操作:僅允許填寫表單,禁止其他修改
signature.DocumentPermissions = PdfCertificationFlags.AllowFormFill.value | PdfCertificationFlags.ForbidChanges.value
# 配置可信時(shí)間戳服務(wù)
signature.ConfigureTimestamp("https://freetsa.org/tsr")
doc.SaveToFile("SignedByTimestamp.pdf")
doc.Dispose()
DocumentPermissions 是這里的一個(gè)實(shí)用屬性,它以證書化簽名的方式限定簽署后允許的操作。示例中的組合表示"允許繼續(xù)填寫表單字段,但禁止其他任何改動(dòng)",適合審批完成后仍需收集信息、又要防止內(nèi)容被篡改的表單類文檔。
驗(yàn)證已簽名的文檔
拿到一份簽名文檔后,可以遍歷其表單中的簽名字段,逐個(gè)校驗(yàn)簽名是否有效。
from spire.pdf import *
doc = PdfDocument()
doc.LoadFromFile("SignedDocument.pdf")
# 訪問(wèn)文檔表單
formWidget = PdfFormWidget(doc.Form)
if formWidget.FieldsWidget.Count > 0:
for i in range(formWidget.FieldsWidget.Count):
field = formWidget.FieldsWidget.get_Item(i)
if isinstance(field, PdfField):
signatureField = PdfSignatureFieldWidget(field)
# 用字段全名驗(yàn)證對(duì)應(yīng)簽名
valid = doc.VerifySignature(signatureField.FullName)
print("簽名有效" if valid else "簽名無(wú)效")
doc.Dispose()
VerifySignature 會(huì)重新計(jì)算文檔內(nèi)容的摘要并與簽名中記錄的值比對(duì):如果文檔在簽署之后被改動(dòng),返回結(jié)果就是無(wú)效。這一步是數(shù)字簽名"防篡改"承諾的最終落地。
實(shí)用建議
- 證書密碼不要硬編碼:示例中為了演示直接寫在代碼里,實(shí)際項(xiàng)目應(yīng)從環(huán)境變量或密鑰管理服務(wù)讀取。
- 坐標(biāo)系統(tǒng):簽名框坐標(biāo)以頁(yè)面左下角為原點(diǎn),向上為 y 正方向,與常見的屏幕坐標(biāo)相反,放置時(shí)注意換算。
- 簽名順序:一份文檔可以有多個(gè)簽名。后簽署的簽名會(huì)把先前的簽名內(nèi)容一并納入校驗(yàn)范圍,因此簽署順序會(huì)影響驗(yàn)證邏輯。
- 及時(shí)釋放資源:處理完成后調(diào)用
Dispose()釋放文檔占用的句柄,避免批量任務(wù)中文件被占用。
總結(jié)
本文圍繞 PDF 數(shù)字簽名的常見需求,介紹了可見簽名、隱藏簽名、帶時(shí)間戳簽名以及簽名驗(yàn)證四種操作。它們的核心都建立在證書文件與文檔內(nèi)容的綁定之上:PdfOrdinarySignatureMaker 負(fù)責(zé)普通簽署,Security_PdfSignature 在此基礎(chǔ)上補(bǔ)充了時(shí)間戳和權(quán)限控制,而 VerifySignature 則完成校驗(yàn)閉環(huán)。
在此基礎(chǔ)上,可以進(jìn)一步結(jié)合表單字段、文檔權(quán)限和長(zhǎng)期驗(yàn)證(LTV)等能力,構(gòu)建出適合合同管理、審批流轉(zhuǎn)等場(chǎng)景的自動(dòng)化簽署方案。
到此這篇關(guān)于使用 Python 對(duì) PDF 文檔進(jìn)行數(shù)字簽名的方法的文章就介紹到這了,更多相關(guān)Python PDF數(shù)字簽名內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python time.strptime格式化實(shí)例詳解
在本篇文章里小編給大家整理的是一篇關(guān)于python time.strptime格式化實(shí)例詳解內(nèi)容,對(duì)此有興趣的朋友們可以學(xué)習(xí)參考下。2021-02-02
pytorch查看torch.Tensor和model是否在CUDA上的實(shí)例
今天小編就為大家分享一篇pytorch查看torch.Tensor和model是否在CUDA上的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-01-01
pytorch模型訓(xùn)練的時(shí)候GPU使用率不高的問(wèn)題
這篇文章主要介紹了pytorch模型訓(xùn)練的時(shí)候GPU使用率不高的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-09-09
Python模擬鼠標(biāo)點(diǎn)擊實(shí)現(xiàn)方法(將通過(guò)實(shí)例自動(dòng)化模擬在360瀏覽器中自動(dòng)搜索python)
這篇文章主要介紹了Python模擬鼠標(biāo)點(diǎn)擊實(shí)現(xiàn)方法(將通過(guò)實(shí)例自動(dòng)化模擬在360瀏覽器中自動(dòng)搜索python),需要的朋友可以參考下2017-08-08
使用pycharm連接讀取orcl數(shù)據(jù)庫(kù)的表的操作方法
這篇文章主要介紹了使用pycharm連接讀取orcl數(shù)據(jù)庫(kù)的表的操作方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01
python PaddleSpeech實(shí)現(xiàn)嬰兒啼哭識(shí)別
這篇文章主要為大家介紹了python PaddleSpeech實(shí)現(xiàn)嬰兒啼哭識(shí)別操作詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08

