💡 Ví dụ hoạt động đầy đủ có sẵn trên GitHub:
vault-transit-pdf-signing-python
Tại sao việc ký tự động thất bại trong Đánh giá Quản lý Khóa
Các đội tuân thủ và tài chính ký tài liệu hàng ngàn: hợp đồng vay, sao kê, gói chính sách, thư kiểm toán. Hầu hết không có ai ký bằng cách nhấn nút. Một dịch vụ thực hiện, theo lịch trình, và chứng chỉ đính kèm các tài liệu này mang tên tổ chức. Điều đó khiến khóa ký trở thành một trong những thứ nhạy cảm nhất mà công ty sở hữu, và thường được lưu trong tệp PFX bên cạnh ứng dụng sử dụng nó.
Ký bên ngoài là một khả năng của GroupDocs.Signature cho Python thông qua .NET, cho phép truyền bản tóm tắt tài liệu tới mã bạn cung cấp thay vì ký bằng khóa riêng mà ứng dụng giữ. Nó tồn tại vì cách sắp xếp PFX không chịu được sự kiểm tra kỹ lưỡng. Một tệp là một bản sao, và các bản sao lan truyền: vào ảnh container, pipeline triển khai, bản sao lưu, laptop của nhà phát triển đã gỡ lỗi sự cố sản xuất mùa xuân vừa qua. Bất kỳ ai nắm một trong những bản sao đó và mật khẩu đều có thể ký thay bạn cho đến khi ai đó nhận ra và thu hồi chứng chỉ.
Những gì các đội này cần không phải là một định dạng tệp khác. Họ cần khóa tồn tại ở đúng một nơi, có nhật ký kiểm toán mỗi lần nó được sử dụng, và một dịch vụ ký có thể yêu cầu chữ ký mà không bao giờ được tin cậy với khóa. Đó là mục đích của một trình quản lý khóa như HashiCorp Vault, và nó chỉ hữu ích nếu thư viện tài liệu có thể được chỉ định để ủy thác mật mã.
Tại sao một tệp chứng chỉ được bảo vệ bằng mật khẩu không đủ
Bản năng là khóa chặt PFX: hạn chế quyền truy cập tệp, lưu mật khẩu trong trình quản lý bí mật, mã hóa ổ đĩa. Mỗi bước giúp và không bước nào thay đổi thực tế cốt lõi. Vào thời điểm ký, khóa riêng được tải vào tiến trình, vì vậy một dump bộ nhớ, một lỗ hổng container hoặc một câu lệnh log bất cẩn vẫn có thể lộ nó. Kiểm soát bạn muốn là một khóa không thể đọc được chút nào, không phải một khóa khó đọc hơn.
Engine Transit của Vault cung cấp điều đó. Nó thực hiện mật mã như một dịch vụ: bạn gửi một giá trị, nó ký hoặc mã hoá bằng khóa mà nó giữ, và trả về kết quả. Các khóa tạo bên trong có thể được đánh dấu là không xuất khẩu, và nó không bao giờ lưu trữ những gì nó nhận. GroupDocs.Signature bao phủ nửa còn lại, vì DigitalSignOptions.custom_sign_hash cho phép bạn gắn bộ ký của mình vào quy trình ký PDF.
Cài đặt: GroupDocs.Signature cho Python với Vault Transit
GroupDocs.Signature làm mọi thứ cho đến mật mã. Nó mở PDF, quyết định phạm vi byte mà chữ ký bao phủ, băm phạm vi đó, và gọi bộ ký của bạn với bản tóm tắt. Bộ ký của bạn đưa bản tóm tắt cho Vault và trả về các byte mà Vault tạo. Thư viện nhúng chúng cùng với chứng chỉ và ghi một PDF ký bình thường.
Bạn cần Python 3.11 hoặc 3.13, các gói groupdocs-signature-net và asn1crypto, và Docker cho container Vault ở chế độ dev. Giấy phép GroupDocs là tùy chọn; nếu không có, chế độ đánh giá cho phép tài liệu tối đa 2 trang. Kho mẫu chạy từ đầu đến cuối bằng hai lệnh, và cùng một mã có thể trỏ tới Vault sản xuất bằng cách thay đổi hai biến môi trường.
Xây dựng từng bước
Bước 1 - Đọc khóa ký từ Vault
Ứng dụng yêu cầu Vault cung cấp khóa được phép sử dụng, và nhận lại số phiên bản và khóa công khai. Phần riêng không bao giờ xuất hiện trong câu trả lời.
key = vault.read_key(KEY_NAME)
if key is None:
# First run: enable Transit and create an RSA-2048 key.
vault.enable_transit()
vault.create_key(KEY_NAME, "rsa-2048")
key = vault.read_key(KEY_NAME)
print(f"Signing key: '{KEY_NAME}', version {key.version}")
Đọc phiên bản một lần là mục đích của bước này. Một chứng chỉ chứa một khóa công khai, vì vậy chứng chỉ và mọi chữ ký phải đến từ cùng một phiên bản.
Bước 2 - Tạo chứng chỉ cho khóa không ai có thể xuất
Một chữ ký PDF mang theo chứng chỉ X.509 để người xác thực có thể tìm khóa công khai. Với khóa không xuất khẩu, chứng chỉ được lắp ráp quanh phần công khai và được Vault ký.
tbs_certificate = x509.TbsCertificate({...}) # built around the Vault public key
# Hash locally, then have Vault sign the certificate's own digest.
digest = hashlib.sha256(tbs_certificate.dump()).digest()
signature = vault.sign_hash(key_name, key.version, digest, "sha2-256")
certificate = x509.Certificate({
"tbs_certificate": tbs_certificate,
"signature_algorithm": algorithm,
"signature_value": signature,
})
Chứng chỉ cố ý bắt đầu một ngày sớm hơn hiện tại. Một trình đọc PDF so sánh thời gian ký với ngày bắt đầu đó, và trên một máy cách UTC hai giờ về phía đông, một chứng chỉ được tạo vài giây trước khi ký đã bị Adobe Acrobat báo là đã hết hạn hoặc chưa hợp lệ.
Bước 3 - Ký PDF thông qua bộ ký bên ngoài
certificate_object = DigitalVerifyOptions(
certificate_stream=io.BytesIO(certificate)).certificate
digital_signature = DigitalSignature(certificate=certificate_object)
digital_signature.sign_time = datetime.now().astimezone()
options = DigitalSignOptions()
options.signature = digital_signature
options.custom_sign_hash = VaultSigner(vault, KEY_NAME, key.version)
options.hash_algorithm = HashAlgorithm.SHA256
options.reason = "Document signed with HashiCorp Vault Transit"
with gs.Signature(str(input_pdf)) as signature:
signature.sign(str(output_pdf), options)
Hai dòng đặc thù cho Python. Binding không có kiểu X.509, vì vậy đối tượng chứng chỉ được trả về từ DigitalVerifyOptions; nếu đưa đường dẫn vào DigitalSignOptions sẽ gây lỗi “Specified certificate doesn’t contain private key”. Và sign_time có ý thức múi giờ, vì một giá trị có độ lệch sẽ được ghi vào PDF cùng với nó.
Trong bộ ký, bản tóm tắt được gửi tới Vault với prehashed = true và pkcs1v15. Hai trường này quyết định chữ ký có hợp lệ hay không, và trường đầu tiên sẽ thất bại im lặng khi thiếu.
Bước 4 - Xác minh trước khi bất kỳ thứ gì rời dịch vụ
options = DigitalVerifyOptions(certificate_stream=io.BytesIO(certificate))
with gs.Signature(str(signed_pdf)) as signature:
is_valid = signature.verify(options).is_valid
Ký và xác minh trong cùng một lần chạy biến chế độ lỗi im lặng thành lỗi ngay lập tức. Đối với một pipeline tài liệu, đây là cổng: một tệp không xác minh sẽ không bao giờ tới kho lưu trữ, đối tác hoặc cổng khách hàng.
Tác động kinh doanh: Điều gì thay đổi cho cuộc kiểm toán
| Mối quan tâm | PFX trên máy chủ ứng dụng | Ký qua Vault Transit |
|---|---|---|
| Bản sao của khóa riêng | một bản cho mỗi máy chủ, image, sao lưu và laptop | một, trong Vault |
| Quyền mà ứng dụng ký cần | toàn quyền truy cập vào tệp khóa | đọc khóa, gọi transit/sign |
| Bằng chứng một tài liệu đã được ký | log ứng dụng, nếu ai đó đã thêm chúng | một mục ghi audit Vault cho mỗi chữ ký |
| Phản hồi khi nghi ngờ rò rỉ | thu hồi, phát hành lại, triển khai lại ở mọi nơi | xoay vòng khóa trong Vault, phát hành lại một lần |
| Ai có thể ký thay bạn | bất kỳ ai có tệp và mật khẩu | bất kỳ ai có token Vault hợp lệ |
Dòng cuối cùng là thật sự. Thiết kế này di chuyển bí mật thay vì loại bỏ nó: một token Vault bị đánh cắp vẫn có thể yêu cầu chữ ký. Sự khác biệt là token có thời gian ngắn, có thể thu hồi ở một nơi, giới hạn trong hai thao tác, và mọi lần sử dụng đều được ghi lại. Đó là một điều dễ bảo vệ hơn nhiều trong cuộc đánh giá so với một tệp mà không ai có thể liệt kê các bản sao.
Quy trình thực tế: Thỏa thuận vay được ký bởi một dịch vụ
Một nền tảng cho vay tạo PDF thỏa thuận khi đơn đăng ký được chấp nhận, ký nó và đưa vào kho tài liệu của khách hàng. Trước thay đổi này, dịch vụ ký giữ chứng chỉ công ty và sổ hướng dẫn triển khai có bước sao chép PFX lên các máy chủ mới. Sau đó, dịch vụ giữ token AppRole với hai quyền, và khóa riêng của chứng chỉ chưa bao giờ tồn tại ở bất kỳ nơi nào ngoại trừ Vault.
Khi các kiểm toán viên hỏi có bao nhiêu tài liệu đã ký trong quý vừa qua và bằng gì, câu trả lời đến từ thiết bị audit của Vault thay vì tái tạo log ứng dụng. Khi nhóm xoay vòng khóa, họ xoay vòng ở một nơi và phát hành chứng chỉ mới cho phiên bản mới.
Điều gì tôi nên làm đúng đầu tiên?
Xử lý digest. Tên thuật toán sai sẽ thất bại rõ ràng, Vault trả lời 500 crypto/rsa: input must be hashed message, và tốn một phút. Thiếu cờ prehashed sẽ không gây lỗi nào: Vault sẽ băm lại digest, chữ ký bao phủ giá trị sai, và PDF trông như đã hoàn thành. Xác minh mọi tệp bạn ký và lỗi đó sẽ không còn ẩn nữa.
Các nơi khác mà thiết kế này phù hợp
Hook không biết gì phía sau, vì vậy bốn bước này cũng hoạt động với mô-đun bảo mật phần cứng, KMS đám mây hoặc thẻ thông minh. Tôi đã chuyển bản dựng này từ phiên bản .NET của nó, mong đợi bộ ký cần sửa lại, và phần duy nhất thực sự thay đổi là việc chuyển giao chứng chỉ; phần thân yêu cầu Vault và việc ghim phiên bản vẫn giống nhau. Các đội ngũ trong y tế, chính phủ và bảo hiểm sử dụng nó vì cùng một lý do như tài chính: khóa phải ở nơi có thể chứng minh mục đích sử dụng.
Bắt đầu
- Bắt đầu miễn phí: nhận giấy phép dùng thử, truy cập API đầy đủ
- Đọc hướng dẫn tích hợp:
ký PDF bằng khóa Vault Transit trong Python - Duyệt mã nguồn:
vault-transit-pdf-signing-python - Đặt câu hỏi triển khai trên diễn đàn cộng đồng