數位簽章會記錄誰簽署了文件。受信任的時間戳記會記錄 何時,且該時間來自獨立的時間戳記授權機構(TSA),而非簽署者電腦的時鐘。本教學將示範如何在 Python 中使用帶時間戳記的 XAdES‑T 簽章簽署 Word 文件,然後確認時間戳記已嵌入檔案中。
主要要點
- 設定 兩者
SignOptions.xml_dsig_level = XmlDsigLevel.X_AD_ES_T和SignOptions.timestamp_settings。單獨設定其中一項會產生沒有時間戳記的簽章,且不會有錯誤提示。 - Aspose.Words 在
DigitalSignatureUtil.sign期間請求時間戳記,因此此呼叫需要能連線至 TSA 的網路存取。 - DOCX 和 DOC 檔案可以加上時間戳記。ODT 檔案則不行。
DigitalSignature.is_valid檢查的是簽章本身,而非時間戳記。請另行確認時間戳記。
受信任的時間戳為簽名添加了什麼
每個 Aspose.Words 所建立的簽名都帶有簽署時間,由 SignOptions.sign_time 設定。該值來自簽署者的機器,因此任何對文件提出異議的人也可以對時間提出異議。
XAdES‑T 簽章會加入獨立的證據。文件簽署後,Aspose.Words 會將簽章值的雜湊傳送至時間戳記機構 (TSA)。TSA 會回傳一個 RFC 3161 令牌,該令牌以其自身的憑證簽署,將雜湊與特定時間綁定。此令牌會儲存在簽章內。驗證者隨後即可證明該簽章在當時已存在,這在簽署憑證之後過期或被撤銷時尤為重要。
先決條件
在執行範例之前,請確保您已具備:
pip install --upgrade "aspose-words>=26.9"
- 簽署憑證,使用 PKCS#12 格式(
.pfx或.p12)以及其密碼。 - 時間戳授權機構 URL。 範例使用 FreeTSA(
https://freetsa.org/tsr),這是一個免費的公共 TSA,方便測試。對於正式文件,請使用貴組織或憑證提供者建議的 TSA,因為檢查文件的人必須信任該 TSA 的憑證。 - TSA 憑證,僅在您的 TSA 需要驗證時使用。
如果沒有授權,Aspose.Words 會在評估模式下運行,並受到限制。
臨時授權 可在測試期間移除這些限制。
使用受信任的時間戳對 Word 文件簽名
以下腳本使用 XAdES‑T 簽名對 DOCX 檔案進行簽署,並嵌入來自 TSA 的時間戳。
import datetime
import aspose.words as aw
# Replace these values with your own files and credentials.
INPUT_DOC = "contract.docx"
OUTPUT_DOC = "contract-signed.docx"
CERT_FILE = "signing-cert.pfx"
CERT_PASSWORD = "your-pfx-password"
TSA_URL = "https://freetsa.org/tsr"
TSA_USER = "" # Fill in only if your TSA requires authentication.
TSA_PASSWORD = ""
# Load the signing certificate from a PKCS#12 file.
cert_holder = aw.digitalsignatures.CertificateHolder.create(
file_name=CERT_FILE, password=CERT_PASSWORD)
# Request an XAdES-T signature and point it at a timestamp authority.
sign_options = aw.digitalsignatures.SignOptions()
sign_options.xml_dsig_level = aw.digitalsignatures.XmlDsigLevel.X_AD_ES_T
sign_options.timestamp_settings = aw.digitalsignatures.DigitalSignatureTimestampSettings(
server_url=TSA_URL,
user_name=TSA_USER,
password=TSA_PASSWORD,
timeout=datetime.timedelta(seconds=60), # Default is 100 seconds.
)
# Sign the document. Aspose.Words contacts the TSA during this call.
aw.digitalsignatures.DigitalSignatureUtil.sign(
src_file_name=INPUT_DOC,
dst_file_name=OUTPUT_DOC,
cert_holder=cert_holder,
sign_options=sign_options,
)
print(f"Signed with a trusted timestamp: {OUTPUT_DOC}")
程式碼運作方式
CertificateHolder.create從.pfx檔案中讀取私鑰和憑證鏈。密碼錯誤會在此失敗,於任何簽署開始之前。XmlDsigLevel.X_AD_ES_T告訴 Aspose.Words 建立 XAdES‑T 簽章,這是 XAdES‑EPES 加上簽章時間戳記。DigitalSignatureTimestampSettings保存 TSA URL、可選的使用者名稱與密碼,以及可選的逾時時間。對於接受匿名請求的 TSA,空字串是可以的。如果 TSA 回應 HTTP 認證挑戰,Aspose.Words 會傳送您提供的憑證。DigitalSignatureUtil.sign將簽署的副本寫入OUTPUT_DOC,並保持輸入檔案不變。簽署未簽名的文件:如果輸入已經有簽章,輸出將同時包含現有簽章和新的簽章。
檢查時間戳是否已嵌入
DigitalSignature 物件(由 Aspose.Words 返回)不會公開時間戳,且 is_valid 不會檢查它。 在測試中,即使時間戳記令牌被刻意損壞,文件仍會回報 is_valid 為 True。 要確認時間戳,請檢查存放於 DOCX 套件中的簽章 XML:
import base64
import re
import zipfile
import aspose.words as aw
SIGNED_DOC = "contract-signed.docx"
# 1. Check the signature itself.
for sig in aw.digitalsignatures.DigitalSignatureUtil.load_signatures(SIGNED_DOC):
print(f"Signer: {sig.subject_name} | valid: {sig.is_valid}")
# 2. Check that a timestamp token was embedded, and save it for inspection.
with zipfile.ZipFile(SIGNED_DOC) as package:
for part in package.namelist():
if part.startswith("_xmlsignatures/sig") and part.endswith(".xml"):
xml = package.read(part).decode("utf-8")
match = re.search(r"<(?:\w+:)?EncapsulatedTimeStamp[^>]*>([^<]+)<", xml)
if match:
with open("timestamp-token.der", "wb") as f:
f.write(base64.b64decode(match.group(1)))
print(f"{part}: timestamp embedded (saved to timestamp-token.der)")
else:
print(f"{part}: no timestamp found")
對於已簽名的 DOCX,您應該會看到類似以下的輸出:
Signer: CN=Your Name | valid: True
_xmlsignatures/sig1.xml: timestamp embedded (saved to timestamp-token.der)
要读取 TSA 认证的时间,请将保存的令牌传递给 OpenSSL:
openssl ts -reply -token_in -in timestamp-token.der -token_out -text
Time stamp 行顯示 GMT 中的認證時間,而 TSA 行則標示發行該時間戳的機構。
此檢查讀取 DOCX 包格式。DOC 檔案將其簽名存儲在二進位容器中,因此基於 ZIP 的腳本不適用於它。
疑難排解簽署與時間戳記錯誤
| 症狀 | 可能原因 | 解決方法 |
|---|---|---|
| 簽署成功,但未嵌入時間戳記 | 只設定了 xml_dsig_level = X_AD_ES_T 或 timestamp_settings 其中之一 | 在呼叫 sign 之前同時設定兩者。使用 XML_D_SIG 或 X_AD_ES_EPES 時,時間戳記設定會被忽略。 |
RuntimeError 提及 (401) Unauthorized | TSA 需要認證資訊,或認證資訊錯誤 | 傳遞由您的 TSA 提供者發放的使用者名稱和密碼。 |
RuntimeError 提及連線被拒絕或代理錯誤 | TSA URL 錯誤,或防火牆或代理阻擋了請求 | 檢查 URL 並確認執行腳本的機器能夠連線至 TSA。 |
RuntimeError 提及 The operation has timed out | TSA 未在逾時時間內回應 | 重試,或將較長的 timeout 傳遞給 DigitalSignatureTimestampSettings。 |
| 錯誤發生後仍留下空的輸出檔案 | sign 在 TSA 請求失敗前就已建立目標檔案 | 在重試前刪除目標檔案,或寫入暫存路徑,成功呼叫後再重新命名。 |
RuntimeError 表示此檔案格式不支援時間戳記 | 輸入檔為 ODT 檔案 | 為 DOCX 或 DOC 檔案加上時間戳記,或轉換為 PDF 並使用下方描述的 PDF 簽署流程。 |
在 Linux 上出現 No usable version of libssl was found,或因缺少 ICU 套件而崩潰 | Python 套件所捆綁的 .NET 執行環境需要 OpenSSL 1.1 與受支援的 ICU 版本 | 安裝 OpenSSL 1.1,或安裝受支援的 ICU。若您的應用程式不需要特定文化的格式化,請設定 DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=1 以解決 ICU 錯誤。 |
替代方案:在 PDF 輸出中為簽名加上時間戳記
如果您的收件者需要 PDF 而不是已簽署的 Word 檔案,您不需要 DigitalSignatureUtil。在儲存時透過設定 PdfSaveOptions.digital_signature_details.timestamp_settings 為 PdfDigitalSignatureTimestampSettings 物件,即可對 PDF 進行簽名與時間戳記。此方法的可用時間遠長於 26.9。此 PdfDigitalSignatureTimestampSettings 參考文件 包含完整範例。
下一步
若要新增簽名行、使用簽名行圖像簽署,或移除現有簽名,請參閱 Aspose.Words for Python 文件中的 使用數位簽章。
常見問題
受信任的時間戳記對數位簽章有什麼作用?
時間戳記授權機構(TSA)會驗證簽章產生的時間。此時間來自獨立的第三方,而非簽署者的電腦時鐘,並且讓驗證者能證明簽章在簽署憑證過期或被撤銷之前已存在。哪個 Aspose.Words 版本支援在 DigitalSignatureUtil 中使用時間戳記?
Aspose.Words for Python via .NET 的 26.9 版加入了SignOptions.timestamp_settings、XmlDsigLevel.X_AD_ES_T以及DigitalSignatureTimestampSettings類別。較早的版本只能在 PDF 輸出中為簽章加上時間戳記。我是否需要同時設定 xml_dsig_level 和 timestamp_settings?
是的。若僅設定其中一個,Aspose.Words 仍會簽署文件,但不會請求或嵌入時間戳記,且不會拋出錯誤。哪些檔案格式可以加上時間戳記?
使用X_AD_ES_T簽署的 DOCX 與 DOC 檔案會收到時間戳記。若對 ODT 檔案加上時間戳記,則會拋出錯誤,指出該格式不支援時間戳記。is_valid是否確認時間戳記有效?
不是。DigitalSignature.is_valid只檢查簽章本身。若要確認時間戳記,需檢查簽章 XML 是否包含時間戳記代幣,並使用如 OpenSSL 等工具檢查該代幣。如果無法連線至 TSA 會發生什麼情況?
DigitalSignatureUtil.sign會拋出描述網路、驗證或逾時問題的RuntimeError。目標路徑可能只留下空檔案,請在重新嘗試前將其刪除。
