การลงนามในระดับขนาดใหญ่ โดยไม่ลดทอน
Spec: ISO 32000-2, §12.8ISO 32000-2 §12.8Spec: ETSI EN 319 142-1ETSI EN 319 142-1Spec: RFC 5652, §5.1RFC 5652 §5.1
ภาพรวมโดยสังเขป
หัวข้อที่มีชื่อว่า “ภาพรวมโดยสังเขป”การลงนามเอกสารหนึ่งฉบับเป็นการดำเนินการเชิงวิทยาการรหัสลับ การลงนามหนึ่งแสนฉบับภายใต้เส้นตายคือการดำเนินการเดียวกันที่ทำซ้ำ ซึ่งความล้มเหลวที่อันตรายไม่ได้อยู่ที่ “มันช้า” อีกต่อไป แต่อยู่ที่ “หนึ่งในนั้นออกไปโดยไม่ได้ลงนามและไม่มีใครสังเกตเห็น” หน้านี้ว่าด้วยการทำสิ่งที่สองโดยไม่ละทิ้งสิ่งแรก: การลงนามแบบจำนวนมากและพร้อมกันที่ทุกลายเซ็นยังคงถูกต้อง การรันปฏิเสธที่จะ emit ไฟล์ที่มันลงนามไม่ได้ และงานขนาดใหญ่ทำงานต่อจากเดิมแทนที่จะเริ่มใหม่ทั้งหมด
เหตุใดเรื่องนี้จึงสำคัญ
หัวข้อที่มีชื่อว่า “เหตุใดเรื่องนี้จึงสำคัญ”ลายเซ็นเป็นข้อเท็จจริงเฉพาะของแต่ละเอกสาร digest ของมันถูกคำนวณบนช่วงไบต์ที่ประกาศไว้ซึ่งไม่รวมค่าลายเซ็นเอง (Spec: ISO 32000-2, §12.8ISO 32000-2 §12.8) ดังนั้นจึงไม่มีวิธีที่ซื่อตรงในการลงนามเอกสารหนึ่งพันฉบับ “แบบเป็น batch” ในคราวเดียว — แต่ละฉบับพกพา CMS SignedData ของตัวเองบนไบต์ของตัวเอง (Spec: RFC 5652, §5.1RFC 5652 §5.1) ขนาดที่ใหญ่ขึ้นจึงเพิ่มโอกาสที่จะมีสิ่งหนึ่งสิ่งใดผิดพลาดไปอย่างเงียบๆพอดี: key handle ที่ล้มเหลวชั่วครู่ ผู้ออกการประทับเวลาที่หมดเวลา worker ที่ตายไปขณะถือไฟล์ที่เขียนค้างไว้
ผลลัพธ์ที่มีราคาแพงไม่ใช่การ crash การ crash นั้นเสียงดังและคุณก็ลองใหม่ได้ ผลลัพธ์ที่มีราคาแพงคือผลลัพธ์ แบบเงียบ — PDF ที่ไม่ได้ลงนามซึ่งดูเหมือนเสร็จสมบูรณ์นั่งอยู่ในที่จัดเก็บถาวร ถูกค้นพบหลายเดือนต่อมาโดย validator ของผู้ตรวจสอบ เมื่ออยู่ในปริมาณมาก “ลงนามแล้วเกือบหมด” แทบแยกไม่ออกจาก “ลงนามแล้ว” จนกระทั่งฉบับที่สำคัญถูกตรวจสอบ หัวใจทั้งหมดของการลงนามในระดับขนาดใหญ่คือการทำให้ผลลัพธ์นั้นเป็นไปไม่ได้เชิงโครงสร้าง ไม่ใช่เพียงเกิดขึ้นได้ยากในเชิงสถิติ
ฉบับย่อ
หัวข้อที่มีชื่อว่า “ฉบับย่อ”- ทุกเอกสารถูกลงนามเป็นรายฉบับ บนช่วงไบต์ของตัวเอง Batch เป็นคำเชิงการจัดตาราง เวลา ไม่ใช่คำเชิงวิทยาการรหัสลับ ไม่มีลายเซ็นที่ใช้ร่วมกัน
- ระดับเป็นสัญญา ไม่ใช่คำใบ้ คุณระบุชื่อระดับเบสไลน์ของ PAdES และเอนจินผลิต ระดับนั้นตรงตามนั้นให้ทุกเอกสาร หรือไม่ก็ทำให้เอกสารนั้นล้มเหลวอย่างเสียงดัง (Spec: ETSI EN 319 142-1ETSI EN 319 142-1)
- ไปป์ไลน์เป็นแบบ fail-closed เอกสารที่ลงนามอย่างถูกต้องไม่ได้จะไม่ถูกส่งผ่าน ไปในรูปไบต์ดิบ แต่จะถูกกักไว้ ไม่ใช่ส่งต่อ
- ความขนานเป็นรายเอกสาร และปลอดภัยโดยการออกแบบ หน่วยการลงนามไม่ใช้สถานะที่ เปลี่ยนแปลงได้ร่วมกัน worker สองตัวจึงไม่สามารถทำให้เอาต์พุตของกันและกันเสียหายได้
- การรันขนาดใหญ่มีความคงทน เอาต์พุตที่ commit แล้วจะไม่ถูก emit ซ้ำเมื่อ ทำงานต่อ; การรันที่ crash จะดำเนินต่อจาก checkpoint ล่าสุดแทนที่จะลงนามทุกอย่าง ใหม่หมด
แนวทางของ NextPDF ต่อเรื่องนี้
หัวข้อที่มีชื่อว่า “แนวทางของ NextPDF ต่อเรื่องนี้”การออกแบบตั้งอยู่บนการแยกส่วนเพียงข้อเดียว: การผลิตลายเซ็นเป็นขั้นตอนเล็กๆแบบ deterministic ต่อเอกสาร; การรันมันนับพันครั้งอย่างปลอดภัยเป็นขั้นตอนของการ orchestration การแยกทั้งสองส่วนนี้ออกจากกันคือสิ่งที่ทำให้แต่ละส่วนยังคงเรียบง่าย
ขั้นตอนการลงนามคือขั้นตอนที่ต้องไม่มีวันลดทอน คุณร้องขอระดับหนึ่ง — กรณีของ enum SignatureLevel ไม่ใช่ string ที่เอนจินต้องตีความ — และระดับนั้นถูกปฏิบัติในฐานะสัญญาสำหรับ เอกสารนั้น เอนจินผลิตระดับที่ร้องขอหรือหยุดพร้อมข้อผิดพลาดที่ดำเนินการแก้ไขได้ มันจะไม่ลงนามในระดับต่ำกว่าอย่างเงียบๆแล้วปล่อยให้บันทึกอ้างว่าเป็นระดับที่สูงกว่า ความถูกต้องไม่ผ่อนคลายเพียงเพราะมีเอกสารตามมาอีกมาก ลายเซ็นฉบับที่หนึ่งแสนถูกคำนวณอย่างพิถีพิถันเท่ากับฉบับแรกทุกประการ
กฎ fail-closed คือสิ่งที่ทำให้สิ่งนั้นน่าเชื่อถือเมื่ออยู่ในปริมาณมาก เส้นทางการลงนามของ NextPDF ปฏิเสธที่จะ emit สิ่งประดิษฐ์ที่ดูเหมือนน่าเชื่อถือแต่ไม่ได้ลงนามแทนสิ่งที่คุณร้องขอ เส้นทางแอปพลิเคชันที่รองรับคือ Document API ระดับสูง: คุณกำหนดค่าลายเซ็นด้วย Document::setSignature() แล้วร้องขอไบต์ด้วย Document::getPdfData() (หรือ save() / output()) และการเขียนผ่านเดียวนั้นจะ emit PDF ที่ลงนามอย่างถูกต้อง หรือ throw ก่อน ที่จะส่งไบต์กลับมา — ไม่ใช่ไฟล์ที่ไม่ได้ลงนามซึ่งผู้เรียกเชื่อว่าลงนามแล้ว เมื่อนำไปใช้ทั่วทั้ง batch นี่คือกฎที่เปลี่ยน “หนึ่งฉบับหลุดออกไปโดยไม่ได้ลงนาม” จากข้อบกพร่องแฝงแบบเงียบ ให้กลายเป็นงานหนึ่งที่ล้มเหลวและลองใหม่ได้
- Warm the signing material onceOn worker boot, open the key/certificate source and the timestamp client. This cost is paid once per worker, not once per document.
- Enqueue the documentsA queue holds the per-document jobs. The queue is the throughput dial — signing workers scale horizontally behind it.
- Render and sign one documentA disposable unit renders the document, then signs it over its own byte range at the requested PAdES level. Nothing is shared with the next document.
- Commit on success, hold on failureA correctly-signed file commits once. A document that could not be signed is failed and retried — never emitted as unsigned bytes.
- Checkpoint, and resume on crashA durable run records what has committed. After a crash it continues from the last checkpoint instead of re-signing the whole batch.
Core มอบความถูกต้องเชิงวิทยาการรหัสลับให้คุณ: การลงนาม CMS ด้วยซอฟต์แวร์และ PAdES B-B (พร้อม B-T ผ่าน timestamp client) ที่แต่ละเอกสารถูกลงนามเป็นรายฉบับและ fail-closed ส่วน การ orchestration ที่ทำให้การรันขนาดใหญ่มีความคงทน ทำงานพร้อมกัน และเป็น exactly-once — เอนจินเรนเดอร์ที่ปราศจาก side-effect บวกกับ committer, checkpoint, idempotency และ dead-letter store — คือโมดูล Stream ในเอดิชันขั้นสูง; การลงนามที่หนุนด้วยฮาร์ดแวร์ผ่าน HSM หรือ cloud KMS ก็เป็น seam ของเอดิชันขั้นสูงเช่นกัน Core พิสูจน์ว่าแต่ละลายเซ็นถูกต้อง; เอดิชันขั้นสูงทำให้หนึ่งล้านลายเซ็นนั้นอยู่รอดได้
ตัวอย่างการใช้งานจริง
หัวข้อที่มีชื่อว่า “ตัวอย่างการใช้งานจริง”รูปทรงด้านล่างคือหน่วยการลงนามต่อเอกสารภายในลูป batch แต่ละรอบลงนามเอกสารหนึ่งฉบับที่ระดับซึ่งระบุชื่อไว้ และให้ผลลัพธ์ที่ลงนามอย่างถูกต้อง หรือทำให้งานนั้นล้มเหลว — มันไม่เคยส่งคืนไบต์ที่ไม่ได้ลงนามแต่งตัวให้ดูเหมือนผลลัพธ์
<?php
declare(strict_types=1);
use NextPDF\Contracts\DocumentFactoryInterface;use NextPDF\Security\Signature\CertificateInfo;use NextPDF\Security\Signature\SignatureLevel;use NextPDF\Exception\SignatureException;use Psr\Log\LoggerInterface;
/** * One signing-batch iteration: render, sign at a named level, commit or fail. * * The factory and the certificate source ($certInfo, the warmed signing * material) are process-lifetime singletons; the document is disposable. A * document that cannot be signed at the requested level fails this job loudly — * it is never committed unsigned. * * @param iterable<int, callable(\NextPDF\Core\Document): \NextPDF\Core\Document> $jobs */function signBatch( DocumentFactoryInterface $factory, CertificateInfo $certInfo, LoggerInterface $logger, iterable $jobs,): void { // The level is an explicit, ordered contract — not a flag we hope is honoured. $level = SignatureLevel::PAdES_B_T;
foreach ($jobs as $jobId => $build) { // Fresh, disposable unit — shares the warmed signing material only. $doc = $factory->create(); $doc = $build($doc);
try { // Sign over this document's own byte range, at exactly $level, // or throw. There is no "signed lower, reported higher" path. $doc->setSignature(certInfo: $certInfo, level: $level); $signed = $doc->getPdfData(); } catch (SignatureException $e) { // Fail-closed: this document does NOT continue as unsigned bytes. // The job is failed and left for retry / dead-letter handling. $logger->error('pdf.sign.failed', ['job_id' => $jobId, 'reason' => $e->getMessage()]); continue; }
// Only a correctly-signed result reaches the commit step. commitSignedOutput($jobId, $signed); unset($doc, $signed); // release per-document state before the next iteration
$logger->info('pdf.sign.committed', ['job_id' => $jobId, 'level' => $level->value]); }}catch คือบรรทัดที่รับน้ำหนัก มันคือความแตกต่างระหว่างการรันที่กักเอกสารที่มันลงนามไม่ได้เอาไว้ กับการรันที่ส่งมันออกไปอยู่ดี continue ไม่ได้กลบเกลื่อนความล้มเหลว — งานนั้นถูกบันทึกไว้และถูกทิ้งไว้ให้ลองใหม่ ดังนั้น batch จึงเสร็จสิ้นพร้อมรายการที่ทราบและครบถ้วนว่าฉบับใดลงนามแล้วและฉบับใดยังไม่ ไม่มีวันมีช่องว่างแบบเงียบๆ
ความเข้าใจผิดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ความเข้าใจผิดที่พบบ่อย”ความเข้าใจผิดประการแรกคือ “batch signing” หมายถึงลายเซ็นหนึ่งที่นำไปใช้กับหลายไฟล์ มันไม่ใช่ และระบบใดก็ตามที่อ้างเช่นนั้นก็ไม่ได้กำลังผลิตลายเซ็น PAdES ที่ถูกต้อง — digest ของแต่ละเอกสารผูกอยู่กับไบต์ของตัวเอง (Spec: ISO 32000-2, §12.8ISO 32000-2 §12.8) Batch เป็นเรื่องเกี่ยวกับ จำนวนเท่าใด และ เร็วเพียงใด ล้วนๆ ไม่เคยเกี่ยวกับการใช้หน่วยเชิงวิทยาการรหัสลับร่วมกัน
ประการที่สองคือการคิดว่าความขนานหมายถึงการผ่อนคลายความถูกต้องเพื่อความเร็ว — ว่าตัวลงนามที่เร็วต้องตัดมุมที่ตัวลงนามที่พิถีพิถันไม่ตัด มันไม่เป็นเช่นนั้น เพราะหน่วยการลงนามไม่ใช้สถานะที่เปลี่ยนแปลงได้ร่วมกัน การรันมันแบบขนานจึงเปลี่ยนตารางเวลา ไม่ใช่ไบต์ ลายเซ็นแบบขนานแต่ละตัวถูกคำนวณด้วยความเข้มงวดเท่ากับลายเซ็นเดี่ยว ความขนานอยู่ใน orchestration ที่ห่อหุ้มพวกมัน
ประการที่สามคือการคิดว่าความคงทนเป็นสิ่งที่คุณมาแปะติดทีหลังจากการรันข้ามคืนที่ล้มเหลวครั้งแรก เมื่อถึงตอนนั้นคุณก็เสียการรันนั้นไปแล้ว ไปป์ไลน์ที่ทำงานต่อได้ต้องรู้เป็นรายเอกสารว่าสิ่งใด commit แล้วและสิ่งใดยังไม่ ก่อน ที่จะ crash — ซึ่งเป็นสิ่งที่ checkpoint และ idempotency store มีอยู่เพื่อบันทึกไว้พอดี
ขีดจำกัดและขอบเขต
หัวข้อที่มีชื่อว่า “ขีดจำกัดและขอบเขต”- แต่ละลายเซ็นเป็นรายเอกสารและผูกพันกับมาตรฐาน; ไม่มีทางลัดแบบ batch ปริมาณ เปลี่ยนการจัดตารางเวลา ไม่ใช่หน่วยเชิงวิทยาการรหัสลับ NextPDF ลงนามทุกเอกสาร บนช่วงไบต์ของตัวเอง
- Core ทำการลงนาม CMS ด้วยซอฟต์แวร์และ PAdES B-B (B-T ผ่าน timestamp client) ส่วนเอนจินเรนเดอร์และลงนามที่คงทน ทำงานพร้อมกัน และ exactly-once คือโมดูล Stream ในเอดิชันขั้นสูง; การดูแลครอบครองคีย์ที่หนุนด้วย HSM/KMS เป็น seam ของ เอดิชันขั้นสูง หน้านี้ไม่ได้อ้างว่าการ orchestration นั้นเป็น Core
- Fail-closed เป็นพฤติกรรมของเอนจิน ไม่ใช่การรับประกันเกี่ยวกับการเดินสายของคุณ
NextPDF ปฏิเสธที่จะ emit ไฟล์ที่ไม่ได้ลงนามแต่ถูกเชื่อว่าลงนามแล้ว และนำเสนอ
เส้นทางการลงนามที่รองรับ ไปป์ไลน์ที่ดักข้อผิดพลาดที่เกิดขึ้นแล้ว commit ต่อไป
อยู่ดี ได้เลือกที่จะทำลายการรับประกันนั้น — กรอบที่
catch/continueใน ตัวอย่างมีอยู่เพื่อป้องกัน - ระดับ PAdES ถูกบังคับใช้เป็นรายเอกสาร ไม่ใช่ถูกรับรองสำหรับทั้งการรัน เอนจิน ผลิตระดับเบสไลน์ที่ร้องขอหรือไม่ก็ล้มเหลว; นั่นคือการบังคับใช้เชิงโครงสร้าง ไม่ใช่ คำตัดสินความสอดคล้องจากบุคคลที่สามสำหรับไฟล์ที่ผลิตออกมา ลำดับการไล่ระดับเองนั้น กล่าวถึงใน โปรไฟล์เบสไลน์ของ PAdES
- คิว การดูแลครอบครองคีย์ ผู้ออกการประทับเวลา และ object store เป็นของคุณ NextPDF จัดหาความถูกต้องของการลงนามต่อเอกสาร และในเอดิชันขั้นสูงก็จัดหา primitive ของ การ orchestration ที่คงทน มันไม่ได้รันโครงสร้างพื้นฐานของคุณหรือรับประกัน TSA ของคุณ
| Edition | Availability |
|---|---|
| Core | การลงนาม CMS ด้วยซอฟต์แวร์ต่อเอกสาร PAdES B-B (B-T พร้อม timestamp client) ลงนามเป็นรายฉบับบนช่วงไบต์ของแต่ละเอกสาร fail-closed ป้องกันเอาต์พุตที่ไม่ได้ ลงนามแบบเงียบ การลงนามต่อเอกสารแบบธรรมดาไม่จำเป็นต้องใช้ระดับเชิงพาณิชย์ |
| Pro | เพิ่มโมดูล Stream: เอนจินเรนเดอร์ที่ปราศจาก side-effect บวกกับ committer, checkpoint, idempotency และ dead-letter store ที่คงทน — การรัน batch ที่ ทำงานพร้อมกัน ปลอดภัยต่อ crash และ exactly-once ซึ่งทำงานต่อจากเดิมแทนที่จะ เริ่มใหม่ |
| Enterprise | เพิ่มการดูแลครอบครองคีย์ที่หนุนด้วยฮาร์ดแวร์ (HSM ผ่าน PKCS#11 หรือ cloud KMS) เพื่อให้คีย์ส่วนตัวไม่เคยออกจากอุปกรณ์ และระดับ PAdES ระยะยาว (B-LT, B-LTA) ที่ทำให้คลังเก็บถาวรปริมาณสูงตรวจสอบยืนยันได้นานหลายทศวรรษ |
เอกสารที่เกี่ยวข้อง
หัวข้อที่มีชื่อว่า “เอกสารที่เกี่ยวข้อง”- การสร้างเอกสารปริมาณสูง — โมเดล batch แบบเข้าคิวที่มีหน่วยความจำในขอบเขตจำกัด ซึ่งหน้านี้ลงนามต่อยอด จากมัน; อ่านก่อนเพื่อทำความเข้าใจวินัยด้าน throughput และการวัดผล
- โปรไฟล์เบสไลน์ของ PAdES — สิ่งที่ แต่ละระดับ (B-B ถึง B-LTA) เพิ่มเข้ามา เพื่อให้คุณลงนามที่ระดับซึ่งข้อผูกพันต้องการ
- ลายเซ็นอยู่ใน PDF อย่างไร — รากฐานด้าน byte-range และพจนานุกรมที่ทำให้ลายเซ็นเป็นรายเอกสาร
- การลงนามที่หนุนด้วย HSM — จุดที่ขอบเขต ของคีย์ส่วนตัวอยู่เมื่อวัสดุการลงนามอยู่ในฮาร์ดแวร์
- Stream (Pro) — เอนจินเรนเดอร์ที่คงทน ทำงาน พร้อมกัน และ exactly-once ที่เปลี่ยนหน่วยการลงนามเดียวให้เป็นการรันที่ทำงาน ต่อได้
อภิธานศัพท์
หัวข้อที่มีชื่อว่า “อภิธานศัพท์”- Batch signing — การลงนามเอกสารจำนวนมากตามกำหนดเวลา เป็นแนวคิดเชิงการจัด ตารางเวลา; แต่ละเอกสารยังคงถูกลงนามเป็นรายฉบับบนไบต์ของตัวเอง
- Fail-closed — เมื่อเกิดความล้มเหลวที่มิฉะนั้นจะสร้างเอาต์พุตที่ไม่ได้ลงนาม หรือผิด ไปป์ไลน์จะกักเอกสารไว้และรายงาน แทนที่จะส่งต่อมันไปในรูปไบต์ดิบ
- Exactly-once commit — คุณสมบัติของไปป์ไลน์ที่คงทนซึ่งเอาต์พุตที่ลงนามอย่าง ถูกต้องถูกเผยแพร่หนึ่งครั้งและไม่ถูก emit ซ้ำเมื่อการรันที่ crash ทำงานต่อ
- Checkpoint — บันทึกที่คงทนต่อเอกสารว่าสิ่งใด commit แล้ว เพื่อให้การรัน ดำเนินต่อจากจุดที่หยุดได้แทนที่จะลงนามทุกอย่างใหม่
- CMS SignedData — คอนเทนเนอร์เชิงวิทยาการรหัสลับสำหรับลายเซ็นบนเนื้อหา (สามารถพกพาผู้ลงนามได้หลายราย); ไปป์ไลน์นี้ผลิตลายเซ็น PDF ของผู้ลงนามหนึ่งราย ต่อเอกสาร ซึ่งคือหน่วยต่อเอกสารที่ batch ผลิตขึ้น
- PAdES — PDF Advanced Electronic Signatures ชุดโปรไฟล์ของ ETSI EN 319 142 สำหรับการลงนาม PDF; ระดับเบสไลน์ของมันไล่ตั้งแต่ B-B ถึง B-LTA