💡 Contoh lengkap yang berfungsi tersedia di GitHub: vault-transit-pdf-signing-python
Mengapa Penandatanganan Otomatis Gagal dalam Tinjauan Penjagaan Kunci
Tim kepatuhan dan operasi keuangan menandatangani dokumen dalam jumlah ribuan: perjanjian pinjaman, pernyataan, paket kebijakan, surat audit. Hampir tidak ada yang ditandatangani oleh orang yang mengklik tombol. Sebuah layanan yang melakukannya, sesuai jadwal, dan sertifikat yang terlampir pada dokumen tersebut memuat nama organisasi. Hal ini menjadikan kunci penandatanganan salah satu hal paling sensitif yang dimiliki perusahaan, dan biasanya disimpan dalam file PFX di samping aplikasi yang menggunakannya.
Penandatanganan eksternal adalah kemampuan GroupDocs.Signature untuk Python via .NET yang mengirimkan digest dokumen ke kode yang Anda sediakan alih-alih menandatangani dengan kunci pribadi yang dimiliki aplikasi. Fitur ini ada karena pengaturan PFX tidak bertahan di bawah pengawasan. Sebuah file adalah salinan, dan salinan tersebut menyebar: ke dalam image kontainer, pipeline penyebaran, cadangan, laptop pengembang yang men-debug masalah produksi musim semi lalu. Siapa pun yang memegang salah satu salinan itu dan kata sandinya dapat menandatangani atas nama Anda sampai ada yang menyadari dan mencabut sertifikat.
Apa yang dibutuhkan tim-tim ini bukan format file yang berbeda. Mereka membutuhkan kunci yang hanya ada di satu tempat, dengan jejak audit setiap kali digunakan, dan layanan penandatanganan yang dapat meminta tanda tangan tanpa pernah dipercaya dengan kunci tersebut. Itulah tujuan manajer kunci seperti HashiCorp Vault, dan hal itu hanya membantu jika perpustakaan dokumen dapat diberi tahu untuk mendelegasikan kriptografi.
Mengapa File Sertifikat yang Dilindungi Kata Sandi Tidak Cukup
Instingnya adalah mengunci PFX: batasi izin file, simpan kata sandi di manajer rahasia, enkripsi volume. Setiap langkah membantu dan tidak ada yang mengubah fakta inti. Pada saat penandatanganan, kunci pribadi dimuat ke dalam proses, sehingga dump memori, pelarian kontainer, atau pernyataan log yang ceroboh masih dapat mengeksposnya. Kontrol yang Anda inginkan adalah kunci yang tidak dapat dibaca sama sekali, bukan kunci yang lebih sulit dibaca.
Mesin Transit Vault menyediakan hal itu. Ia melakukan kriptografi sebagai layanan: Anda mengirim nilai, ia menandatangani atau mengenkripsi dengan kunci yang dimilikinya, dan mengembalikan hasilnya. Kunci yang dibuat di dalamnya dapat ditandai tidak dapat diekspor, dan ia tidak pernah menyimpan apa yang diterimanya. GroupDocs.Signature menutupi setengah lainnya, karena DigitalSignOptions.custom_sign_hash memungkinkan Anda menyambungkan penandatangan Anda sendiri ke pipeline penandatanganan PDF.
Penyiapan: GroupDocs.Signature untuk Python dengan Vault Transit
GroupDocs.Signature melakukan semua hal hingga kriptografi. Ia membuka PDF, menentukan rentang byte yang ditandatangani, menghitung hash rentang tersebut, dan memanggil penandatangan Anda dengan digest. Penandatangan Anda menyerahkan digest ke Vault dan mengembalikan byte yang dihasilkan Vault. Perpustakaan menyematkannya bersama sertifikat dan menulis PDF yang ditandatangani secara normal.
Anda memerlukan Python 3.11 atau 3.13, paket groupdocs-signature-net dan asn1crypto, serta Docker untuk kontainer Vault mode dev. Lisensi GroupDocs bersifat opsional; tanpa lisensi, mode evaluasi menerima dokumen hingga 2 halaman. Repositori contoh berjalan end‑to‑end dengan dua perintah, dan kode yang sama dapat diarahkan ke Vault produksi dengan mengubah dua variabel lingkungan.
Membangun Langkah demi Langkah
Langkah 1 - Baca kunci penandatanganan dari Vault
Aplikasi meminta Vault kunci yang diizinkan untuk digunakan, dan menerima nomor versi serta kunci publik. Setengah pribadi tidak pernah menjadi bagian dari jawaban.
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}")
Membaca versi sekali adalah tujuan langkah ini. Sebuah sertifikat memuat satu kunci publik, sehingga sertifikat dan setiap tanda tangan harus berasal dari versi yang sama.
Langkah 2 - Buat sertifikat untuk kunci yang tidak dapat diekspor oleh siapa pun
Tanda tangan PDF membawa sertifikat X.509 agar verifier dapat menemukan kunci publik. Dengan kunci yang tidak dapat diekspor, sertifikat dirakit di sekitar setengah publik dan ditandatangani oleh Vault.
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,
})
Sertifikat sengaja dimulai satu hari lebih awal daripada sekarang. Pembaca PDF membandingkan waktu penandatanganan dengan tanggal mulai tersebut, dan pada mesin dua jam di timur UTC sebuah sertifikat yang dibuat beberapa detik sebelum penandatanganan dilaporkan oleh Adobe Acrobat sebagai kedaluwarsa atau belum berlaku.
Langkah 3 - Tanda tangani PDF melalui penandatangan eksternal
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)
Dua baris khusus untuk Python. Binding tidak memiliki tipe X.509, sehingga objek sertifikat keluar dari DigitalVerifyOptions; memberikan path ke DigitalSignOptions malah memunculkan error “Specified certificate doesn’t contain private key”. Dan sign_time sengaja dibuat sadar zona waktu, karena nilai dengan offset ditulis ke dalam PDF bersamanya.
Di dalam penandatangan, digest dikirim ke Vault dengan prehashed = true dan pkcs1v15. Kedua bidang tersebut menentukan apakah tanda tangan valid, dan yang pertama gagal secara diam ketika tidak ada.
Langkah 4 - Verifikasi sebelum apa pun keluar dari layanan
options = DigitalVerifyOptions(certificate_stream=io.BytesIO(certificate))
with gs.Signature(str(signed_pdf)) as signature:
is_valid = signature.verify(options).is_valid
Menandatangani dan memverifikasi dalam satu run mengubah mode kegagalan diam menjadi mode langsung. Untuk pipeline dokumen ini adalah gerbang: file yang tidak terverifikasi tidak pernah mencapai arsip, pihak lawan, atau portal pelanggan.
Dampak Bisnis: Apa yang Berubah untuk Audit
| Kekhawatiran | PFX pada host aplikasi | Penandatanganan melalui Vault Transit |
|---|---|---|
| Salinan kunci pribadi | satu per host, image, backup, dan laptop | satu, di dalam Vault |
| Hak yang dibutuhkan aplikasi penandatangan | akses penuh ke file kunci | baca kunci, panggil transit/sign |
| Bukti dokumen telah ditandatangani | log aplikasi, jika ada yang menambahkannya | satu entri audit Vault per tanda tangan |
| Respons terhadap kebocoran yang dicurigai | cabut, terbitkan ulang, redeploy di semua tempat | rotasi kunci di Vault, terbitkan ulang sekali |
| Siapa yang dapat menandatangani atas nama Anda | siapa saja yang memiliki file dan kata sandi | siapa saja yang memegang token Vault yang valid |
Baris terakhir adalah yang paling jujur. Desain ini memindahkan rahasia alih-alih menghilangkannya: token Vault yang dicuri masih dapat meminta tanda tangan. Perbedaannya, token bersifat pendek umur, dapat dicabut di satu tempat, dibatasi untuk dua operasi, dan setiap penggunaannya tercatat. Itu jauh lebih mudah dipertahankan dalam tinjauan dibandingkan file yang salinannya tidak dapat dihitung.
Alur Kerja Nyata: Perjanjian Pinjaman yang Ditandatangani oleh Layanan
Platform pinjaman menghasilkan PDF perjanjian ketika aplikasi disetujui, menandatanganinya, dan menaruhnya ke dalam vault dokumen pelanggan. Sebelum perubahan ini, layanan penandatangan memegang sertifikat perusahaan dan runbook penyebaran memiliki langkah menyalin PFX ke host baru. Setelah perubahan, layanan memegang token AppRole dengan dua izin, dan kunci pribadi sertifikat tidak pernah ada di mana pun kecuali Vault.
Ketika auditor menanyakan berapa banyak dokumen yang ditandatangani kuartal lalu dan oleh siapa, jawabannya berasal dari perangkat audit Vault alih-alih dari rekonstruksi log aplikasi. Ketika tim merotasi kunci, mereka merotasinya di satu tempat dan mengeluarkan sertifikat baru untuk versi baru.
Apa yang Harus Saya Pastikan Benar Pertama?
Penanganan digest. Nama algoritma yang salah gagal dengan suara keras, dengan Vault menjawab 500 crypto/rsa: input must be hashed message, dan memakan satu menit. Flag prehashed yang hilang tidak menghasilkan error sama sekali: Vault meng-hash ulang digest, tanda tangan menutupi nilai yang salah, dan PDF tampak selesai. Verifikasi setiap file yang Anda tanda tangani dan kegagalan itu tidak lagi tak terlihat.
Tempat Lain yang Cocok untuk Desain Ini
Hook tidak tahu apa yang ada di belakangnya, sehingga empat langkah yang sama bekerja pada modul keamanan perangkat keras, KMS cloud, atau kartu pintar. Saya mem-port build ini dari saudara .NET‑nya dengan harapan penandatangan perlu diubah, dan satu‑satunya bagian yang benar‑benarnya berubah adalah penyerahan sertifikat; badan permintaan Vault dan penetapan versi tetap identik. Tim di bidang kesehatan, pemerintahan, dan asuransi menggunakannya dengan alasan yang sama seperti keuangan: kunci harus berada di tempat yang dapat membuktikan apa yang telah digunakannya.
Memulai
- Mulai gratis: dapatkan lisensi percobaan, akses API penuh
- Baca panduan integrasi: menandatangani PDF dengan kunci Vault Transit di Python
- Telusuri kode: vault-transit-pdf-signing-python
- Ajukan pertanyaan implementasi di forum komunitas