Watch the lesson video: Securing AI Agents with Cryptographic Receipts
(วิดีโอบทเรียนและภาพตัวอย่างจะถูกเพิ่มโดยทีมเนื้อหาของ Microsoft หลังจากรวมแล้ว ให้ตรงกับรูปแบบบทเรียนที่ 14 / 15)
บทเรียนนี้จะครอบคลุม:
หลังจากทำบทเรียนนี้เสร็จ คุณจะรู้วิธี:
สมมติว่าคุณได้เปิดใช้ตัวแทน AI สำหรับ Contoso Travel ตัวแทนจะอ่านคำขอของลูกค้า เรียกใช้ API สายการบินเพื่อดูตัวเลือก และจองที่นั่งในนามของลูกค้า ไตรมาสที่แล้ว ตัวแทนดำเนินการจองไป 50,000 รายการ
วันนี้มีผู้ตรวจสอบเข้ามา เขาถามคำถามง่ายๆ: “แสดงให้ฉันดูว่าตัวแทนของคุณทำอะไรไปบ้าง”
คุณมอบไฟล์บันทึกให้ ผู้ตรวจสอบดูไฟล์แล้วถามคำถามที่ยากกว่า: “ฉันจะทราบได้อย่างไรว่าบันทึกเหล่านี้ไม่ได้ถูกแก้ไข?”
นี่คือปัญหาเส้นทางตรวจสอบ การเปิดใช้งานตัวแทนส่วนใหญ่ในปัจจุบันพึ่งพา:
ไม่มีวิธีใดที่ตอบคำถามผู้ตรวจสอบได้โดยไม่ต้องให้ผู้ตรวจสอบไว้วางใจใครสักคน (คุณ ผู้ให้บริการคลาวด์ ผู้จำหน่ายฐานข้อมูล) สำหรับการใช้งานภายใน อาจจะรับได้ แต่สำหรับงานที่ถูกควบคุม (การเงิน สุขภาพ กิจกรรมภายใต้ EU AI Act) จะไม่ได้รับอนุญาต
ใบเสร็จรับเงินแบบเข้ารหัสแก้ปัญหานี้โดยทำให้การกระทำแต่ละอย่างของตัวแทนสามารถตรวจสอบได้อย่างอิสระ ผู้ตรวจสอบไม่จำเป็นต้องไว้วางใจคุณ แค่มีคีย์สาธารณะและใบเสร็จรับเงินเอง
ใบเสร็จคือวัตถุ JSON ที่บันทึกสิ่งที่ตัวแทนทำ และลงลายเซ็นดิจิทัล
flowchart LR
A[ตัวแทนเรียกใช้เครื่องมือ] --> B[สร้างข้อมูลใบเสร็จรับเงิน]
B --> C[ทำให้ JSON เป็นไปตามมาตรฐาน RFC 8785]
C --> D[แฮช SHA-256]
D --> E[ลงนาม Ed25519]
E --> F[ใบเสร็จพร้อมลายเซ็น]
F --> G[ผู้ตรวจสอบยืนยันแบบออฟไลน์]
G --> H{ลายเซ็นถูกต้องไหม?}
H -- yes --> I[หลักฐานป้องกันการปลอมแปลง]
H -- no --> J[ปฏิเสธใบเสร็จ]
ใบเสร็จขั้นพื้นฐานมีลักษณะดังนี้:
{
"type": "agent.tool_call.v1",
"agent_id": "contoso-travel-bot",
"tool_name": "lookup_flights",
"tool_args_hash": "sha256:a3f9c1...",
"result_hash": "sha256:7b2e1d...",
"policy_id": "contoso-travel-policy-v3",
"timestamp": "2026-04-25T14:30:00Z",
"sequence": 47,
"previous_receipt_hash": "sha256:9d4e6a...",
"signature": {
"alg": "EdDSA",
"sig": "c5af83...",
"public_key": "8f3b2c..."
}
}
มีคุณสมบัติสามอย่างที่ทำงานร่วมกัน:
ลายเซ็น ใบเสร็จนี้ถูกลงลายเซ็นโดยเกตเวย์ของตัวแทนโดยใช้คีย์ส่วนตัว Ed25519 ใครก็ตามที่มีคีย์สาธารณะที่สอดคล้องกันสามารถตรวจสอบลายเซ็นแบบออฟไลน์ได้ การปลอมแปลงข้อมูลใด ๆ จะทำให้ลายเซ็นไม่ถูกต้อง
การเข้ารหัสแบบ canonical ก่อนลงลายเซ็น ใบเสร็จจะถูกจัดรูปแบบโดยใช้ JSON Canonicalization Scheme (JCS, RFC 8785) เพื่อให้แน่ใจว่าสองผู้ใช้งานที่สร้างใบเสร็จทางตรรกะเดียวกันจะได้ผลลัพธ์ไบต์ที่เหมือนกัน หากไม่มีการ canonicalization ตัวแปลง JSON ที่ต่างกันจะสร้างลายเซ็นที่แตกต่างกันสำหรับเนื้อหาเดียวกัน
การเชื่อมโยงลำดับด้วยแฮช ฟิลด์ previous_receipt_hash จะเชื่อมแต่ละใบเสร็จเข้ากับใบเสร็จก่อนหน้า การลบหรือจัดลำดับใหม่ใบเสร็จจะทำให้โซ่เสียหาย ใบเสร็จที่ตามมาทั้งหมดจะถูกทำให้เห็นการปลอมแปลงได้ แม้ลายเซ็นแต่ละอันจะถูกข้ามไป
คุณสมบัติเหล่านี้รวมกันให้ความรับประกันสามประการ:
คุณไม่จำเป็นต้องใช้ไลบรารีพิเศษเพื่อสร้างใบเสร็จ พื้นฐานของฟังก์ชันเข้ารหัสพร้อมใช้งานทั่วไปและตรรกะมีไม่กี่สิบบรรทัดใน Python
แบบฝึกหัดใน code_samples/18-signed-receipts.ipynb จะนำคุณผ่านขั้นตอนทั้งหมด สรุปย่อ:
import json
import hashlib
import base64
from nacl import signing
from jcs import canonicalize # RFC 8785 JSON แบบมาตรฐาน
def b64url_nopad(data: bytes) -> str:
return base64.urlsafe_b64encode(data).decode("ascii").rstrip("=")
def sha256_canonical(obj) -> str:
"""SHA-256 of a Python object's JCS-canonical JSON form."""
return f"sha256:{hashlib.sha256(canonicalize(obj)).hexdigest()}"
# สร้างหรือนำเข้ากุญแจสำหรับเซ็นชื่อ (ในสภาพแวดล้อมจริง เก็บไว้ในตู้เก็บกุญแจ)
signing_key = signing.SigningKey.generate()
verify_key = signing_key.verify_key
# สร้างข้อมูลใบเสร็จ (ยังไม่มีลายเซ็น)
tool_args = {"origin": "SYD", "destination": "LAX"}
tool_result = [{"flight": "QF11", "price": 1850, "stops": 0}]
payload = {
"type": "agent.tool_call.v1",
"agent_id": "contoso-travel-bot",
"tool_name": "lookup_flights",
"tool_args_hash": sha256_canonical(tool_args),
"result_hash": sha256_canonical(tool_result),
"policy_id": "contoso-travel-policy-v3",
"timestamp": "2026-04-25T14:30:00Z",
"sequence": 0,
"previous_receipt_hash": None,
}
# ทำให้เป็นมาตรฐาน, แฮช, เซ็นชื่อ
canonical_bytes = canonicalize(payload)
message_hash = hashlib.sha256(canonical_bytes).digest()
signature_bytes = signing_key.sign(message_hash).signature
# แนบวัตถุลายเซ็นที่มีโครงสร้าง
receipt = {
**payload,
"signature": {
"alg": "EdDSA",
"sig": b64url_nopad(signature_bytes),
"public_key": b64url_nopad(bytes(verify_key)),
},
}
นี่คือกระบวนการลงลายเซ็นทั้งหมด แบบฝึกหัดในโน้ตบุ๊กจะอธิบายแต่ละขั้นตอน
การตรวจสอบคือการทำงานซึ่งตรงกันข้าม:
import base64
import hashlib
from nacl import signing
from nacl.exceptions import BadSignatureError
from jcs import canonicalize
def b64url_decode(s: str) -> bytes:
padding = "=" * ((4 - len(s) % 4) % 4)
return base64.urlsafe_b64decode(s + padding)
def verify_receipt(receipt: dict) -> bool:
# ลายเซ็นเป็นอ็อบเจ็กต์ที่มีโครงสร้าง: {"alg", "sig", "public_key"}.
sig_obj = receipt.get("signature")
if not sig_obj or sig_obj.get("alg") != "EdDSA":
return False
# สร้างโหลดข้อมูลที่ถูกเซ็นจริง ๆ ขึ้นใหม่ (ทุกอย่างยกเว้นลายเซ็น).
payload = {k: v for k, v in receipt.items() if k != "signature"}
canonical_bytes = canonicalize(payload)
message_hash = hashlib.sha256(canonical_bytes).digest()
try:
verify_key = signing.VerifyKey(b64url_decode(sig_obj["public_key"]))
verify_key.verify(message_hash, b64url_decode(sig_obj["sig"]))
return True
except BadSignatureError:
return False
ฟังก์ชันนี้รับใบเสร็จ แล้วคืนค่า True ถ้าลายเซ็นถูกต้อง และ False ถ้าไม่ถูกต้อง ไม่มีการเรียกใช้เครือข่าย ไม่มีการพึ่งพาบริการ ไม่มีความไว้วางใจฝ่ายที่สามใด ๆ
เพื่อดูการตรวจจับการปลอมแปลง โน้ตบุ๊กจะทดลอง:
tool_args_hashนี่เป็นบทพิสูจน์เชิงปฏิบัติว่าใบเสร็จมีความสามารถในการแสดงการปลอมแปลง: การแก้ไขใด ๆ แม้เล็กน้อย จะทำให้ลายเซ็นเสียหาย
ใบเสร็จที่ลงลายเซ็นเพียงใบเดียวปกป้องการกระทำหนึ่งอย่าง ในขณะที่โซ่ของใบเสร็จปกป้องลำดับของการกระทำ
flowchart LR
R0[ใบเสร็จ 0<br/>กำเนิด] --> R1[ใบเสร็จ 1]
R1 --> R2[ใบเสร็จ 2]
R2 --> R3[ใบเสร็จ 3]
R1 -. previous_receipt_hash .-> R0
R2 -. previous_receipt_hash .-> R1
R3 -. previous_receipt_hash .-> R2
แต่ละใบเสร็จจะบันทึกแฮชของใบเสร็จก่อนหน้า เพื่อที่จะลบใบเสร็จหมายเลข 2 อย่างเงียบ ๆ ผู้โจมตีต้อง:
previous_receipt_hash ของใบเสร็จ 3 (ทำให้ลายเซ็นใบเสร็จ 3 ผิดพลาด) หรือถ้าคีย์ส่วนตัวถูกเก็บในฮาร์ดแวร์คีย์วอลต์และคุณเผยแพร่คีย์สาธารณะพร้อมใบเสร็จแต่ละรายการ การโจมตีทั้งสองแบบจะไม่สามารถทำได้โดยไม่ถูกจับได้
โน้ตบุ๊กจะนำทางผ่าน:
previous_receipt_hash ของแต่ละใบตรงกับแฮชจริงของใบเสร็จก่อนหน้านี่คือวิธีที่คุณสร้างเส้นทางตรวจสอบที่ผู้ตรวจสอบภายนอกสามารถตรวจสอบได้โดยไม่ต้องไว้วางใจคุณ
นี่คือส่วนที่สำคัญที่สุดของบทเรียน ใบเสร็จมีพลังแต่พลังนั้นมีขอบเขต
ใบเสร็จพิสูจน์สามอย่าง:
ใบเสร็จไม่พิสูจน์:
policy_id ได้รับการประเมินจริงหรือไม่ หรือจะอนุญาตการกระทำนี้หากตรวจสอบ ใบเสร็จบันทึกสิ่งที่อ้างว่าเป็น ไม่ใช่สิ่งที่บังคับใช้ขอบเขตนี้สำคัญเพราะ:
ความผิดพลาดทั่วไปคือคิดว่า “เรามีใบเสร็จ” หมายความว่า “เราถูกควบคุม” ซึ่งไม่ใช่ ใบเสร็จเป็นรากฐาน การปกครองคือระบบที่คุณสร้างขึ้นบนรากฐานนี้
โค้ด Python ในบทเรียนนี้จึงเขียนให้น้อยที่สุดเพื่อให้คุณอ่านทุกบรรทัดและเข้าใจอย่างแน่ชัด ในการผลิตจริง คุณมีสองทางเลือก:
สร้างบนฟังก์ชันเข้ารหัสพื้นฐานโดยตรง 50 บรรทัดที่คุณเห็นข้างต้นเพียงพอสำหรับหลายๆ กรณีใช้งาน PyNaCl (Ed25519) และแพ็กเกจ jcs (JSON canonical) เป็นไลบรารีที่ได้รับการดูแลและตรวจสอบอย่างดี
ใช้ไลบรารีใบเสร็จในงานจริง โครงการโอเพนซอร์สหลายโครงการใช้รูปแบบเดียวกันโดยมีฟีเจอร์เพิ่มเติม (การหมุนคีย์ การตรวจสอบเป็นชุด การแจกจ่าย JWK Set การผสานกับเครื่องยนต์นโยบาย):
draft-farley-acta-signed-receipts) ซึ่งอยู่ในกระบวนการมาตรฐานprotect-mcp (npm) และ @veritasacta/verify (npm) ให้การดำเนินการใบเสร็จบน Node รวมการลงลายเซ็นและการตรวจสอบแบบออฟไลน์ เพื่อพันตัวเซิร์ฟเวอร์ MCP ใดๆ พร้อมเส้นทางตรวจสอบที่ตรวจจับการปลอมแปลงได้การตัดสินใจระหว่างการเขียนเองกับการใช้ไลบรารีคล้ายกับการตัดสินใจเขียนไลบรารี JWT เองหรือใช้ไลบรารีที่ผ่านการทดสอบ: ทั้งสองวิธีเหมาะสม ไลบรารีช่วยประหยัดเวลาและลดภาระการตรวจสอบ ฟีเจอร์เขียนเองช่วยให้คุณเข้าใจทุกฟังก์ชันอย่างลึกซึ้ง บทเรียนนี้สอนวิธีเขียนเองเพื่อให้เป็นรากฐานของทั้งสองทางเลือก
ทดสอบความเข้าใจก่อนดำเนินการแบบฝึกหัด
1. ใบเสร็จรับเงินถูกลงลายเซ็นด้วยคีย์ส่วนตัว Ed25519 ของตัวแทน ผู้ตรวจสอบมีเพียงคีย์สาธารณะเท่านั้น ผู้ตรวจสอบสามารถตรวจสอบใบเสร็จแบบออฟไลน์ได้หรือไม่?
2. ผู้โจมตีแก้ไขฟิลด์ policy_id ของใบเสร็จเพื่ออ้างว่านโยบายที่ใช้งานเป็นนโยบายที่อนุญาตมากกว่า ลายเซ็นครอบคลุมชุดข้อมูลต้นฉบับ เกิดอะไรขึ้นตอนตรวจสอบ?
3. ทำไมใบเสร็จจึงรวม tool_args_hash และ result_hash แทนที่จะเก็บอาร์กิวเมนต์และผลลัพธ์ดิบ?
4. ฟิลด์ previous_receipt_hash เชื่อมแต่ละใบเสร็จเข้ากับใบเสร็จก่อนหน้า หากผู้โจมตีกำจัดใบเสร็จหนึ่งใบในโซ่อย่างเงียบ ๆ สิ่งใดจะไม่ถูกต้อง?
5. ใบเสร็จรับเงินถูกตรวจสอบเรียบร้อยแล้ว นั่นพิสูจน์ว่าการกระทำของตัวแทนถูกต้อง สมเหตุสมผล หรือปฏิบัติตามนโยบายหรือไม่?
เปิด code_samples/18-signed-receipts.ipynb และทำสี่ส่วนนี้ให้ครบ:
ความท้าทายเสริม 1: ขยายสคีมาของใบเสร็จด้วยฟิลด์เพิ่มเติมที่คุณเลือกเอง (เช่น รหัสคำขอสำหรับติดตาม) ปรับตรรกะการลงลายเซ็นแบบ canonical ให้รวมฟิลด์นี้ด้วย และยืนยันว่าใบเสร็จยังสามารถตรวจสอบย้อนกลับได้ จากนั้นแก้ไขฟิลด์หลังการลงลายเซ็นและยืนยันว่าการตรวจสอบล้มเหลว การทดลองนี้จะบังคับให้คุณเข้าใจว่าไบต์ของการเข้ารหัส canonical แต่ละตัวมีผลต่อการลงลายเซ็นอย่างไร ความท้าทายเสริม 2: ทำการแฮช SHA-256 ของใบเสร็จสองใบของคุณเข้าด้วยกัน (เชื่อมต่อไบต์มาตรฐานในลำดับที่แน่นอน) และฝังผลลัพธ์ของดิจิทบนใบเสร็จที่สามก่อนลงลายมือชื่อ ตรวจสอบให้แน่ใจว่าใบเสร็จทั้งสามใบยังคงผ่านการตรวจสอบได้อย่างสมบูรณ์ คุณเพิ่งสร้างหลักฐานการรวมแบบขั้นตอนเดียว: ใครก็ตามที่ถือใบเสร็จที่สามสามารถพิสูจน์ได้ว่าใบเสร็จสองใบแรกมีอยู่ในเวลาที่ลงลายมือชื่อ โดยไม่ต้องเปิดเผยเนื้อหาของมัน นี่คือรูปแบบที่ใบเสร็จเปิดเผยแบบเลือกใช้ในวงกว้าง (Merkle commitments, RFC 6962)
ใบเสร็จทางคริปโตกราฟีมอบเส้นทางตรวจสอบสำหรับเอเยนต์ AI ที่:
ใบเสร็จไม่ใช่ตัวแทนของการตรวจสอบข้อมูลนำเข้า การบังคับใช้กฎระเบียบ หรือโครงสร้างพื้นฐานด้านตัวตน แต่เป็นรากฐานสำหรับชั้นเหล่านั้น เมื่อคุณกำลังปรับใช้เอเยนต์ในงานที่มีการควบคุมขั้นสูง กระบวนการทำงานหลายองค์กร หรือสถานการณ์ที่ผู้ตรวจสอบในอนาคตไม่สามารถเชื่อถือคุณได้ ใบเสร็จคือวิธีที่ทำให้เส้นทางตรวจสอบมีความซื่อสัตย์
ข้อสรุปที่สำคัญที่สุด: ใบเสร็จพิสูจน์ว่าใครพูดอะไรและเมื่อไหร่ โดยไม่ได้พิสูจน์ว่าสิ่งที่พูดนั้นเป็นจริงหรือถูกต้อง จงยึดมั่นในความแตกต่างนี้อย่างเข้มงวด เพราะมันคือตัวแบ่งระหว่างระบบแหล่งที่มาที่ซื่อสัตย์และระบบที่ทำให้เข้าใจผิด
เมื่อคุณพร้อมจะก้าวจากบทเรียนนี้ไปสู่การปรับใช้เอเยนต์ที่ลงลายมือชื่อด้วยใบเสร็จในสภาพแวดล้อมจริง:
https://your-org.example.com/.well-known/agent-keys.jsonเข้าร่วม Microsoft Foundry Discord เพื่อพบปะผู้เรียนคนอื่น ๆ เข้าร่วมชั่วโมงตอบคำถาม และรับคำตอบสำหรับคำถามเกี่ยวกับเอเยนต์ AI ของคุณ
บทเรียนนี้ครอบคลุมการลงลายมือชื่อใบเสร็จเดี่ยวและลำดับสายโซ่แฮชเดียว พื้นฐานเดียวกันนำไปประกอบกันเป็นรูปแบบขั้นสูงหลายแบบที่คุณอาจพบเมื่อการกำกับดูแลของคุณเจริญขึ้น:
authorization_*) และหลังดำเนินการ (result_*) ที่มีลายเซ็นอิสระ เหมาะกับกรณีตัดสินใจอนุญาตและผลลัพธ์ที่สังเกตเห็นผลิตโดยผู้ทำหน้าที่ต่างกันหรือช่วงเวลาต่างกัน สิ่งนี้นำมาประกอบอย่างเสริมกับรูปแบบใบเสร็จที่สอนในบทเรียนนี้result_hash ข้อมูลในโลกจริงมักมีรายละเอียดมากกว่าผลลัพธ์ของเครื่องมือเรียกเดียว: การวิเคราะห์ก่อนตัดสินใจ (การทำนายของโมเดล ตัวเลือกที่พิจารณา หลักฐานและความครบถ้วน ท่าทีความเสี่ยง ห่วงโซ่ความรับผิดชอบ ผลลัพธ์ของประตูอนุญาต) สามารถบรรจุใน payload ที่ปิดผนึกด้วยใบเสร็จใบเดียว วิธีนี้ช่วยรักษารูปแบบใบเสร็จให้น้อยที่สุดในขณะที่ให้สคีมาของ payload พัฒนาได้ตามโดเมนแต่ละประเภทsignature.alg สามารถบรรจุ ML-DSA-65 (มาตรฐานลายเซ็นหลังควอนตัมของ NIST) เมื่อคุณต้องการย้ายระบบ วางแผนช่วงเปลี่ยนผ่านที่ใบเสร็จจะถูกลงลายมือชื่อสองระบบพร้อมกันการสร้างเอเยนต์ใช้งานคอมพิวเตอร์ (CUA)
(กำหนดโดยผู้ดูแลหลักสูตร)
ปฏิเสธความรับผิดชอบ: เอกสารนี้ได้รับการแปลโดยใช้บริการแปลภาษา AI Co-op Translator ขณะที่เราพยายามให้ความถูกต้อง โปรดทราบว่าการแปลโดยอัตโนมัติอาจมีข้อผิดพลาดหรือความไม่ถูกต้อง เอกสารต้นฉบับในภาษาต้นทางควรถูกพิจารณาเป็นแหล่งข้อมูลที่เชื่อถือได้ สำหรับข้อมูลที่สำคัญ แนะนำให้ใช้การแปลโดยมนุษย์มืออาชีพ เราไม่รับผิดชอบต่อความเข้าใจผิดหรือการตีความที่ผิดพลาดที่เกิดขึ้นจากการใช้การแปลนี้