Oglejte si video lekcije: Zavarovanje AI agentov s kriptografskimi prejemki
(Video lekcije in sličica bosta dodana s strani Microsoftove ekipe za vsebino po združitvi, v skladu z vzorcem lekcije 14 / 15.)
Ta lekcija bo zajemala:
Po zaključku te lekcije boste znali:
Predstavljajte si, da ste uvedli AI agenta za Contoso Travel. Agent bere zahteve strank, kliče API za lete za iskanje možnosti in rezervira sedeže v imenu stranke. V zadnjem četrtletju je agent obdelal 50.000 rezervacij.
Danes pride revizor. Postavi preprosto vprašanje: “Pokažite mi, kaj je vaš agent storil.”
Predložite svoje datoteke dnevnika. Revizor jih pregleda in postavi težje vprašanje: “Kako vem, da ti dnevniki niso bili spremenjeni?”
To je problem revizijske sledi. Večina današnjih uvedb agentov se zanaša na:
Nobeden od teh ne more na vprašanje revizorja odgovoriti brez zahteve po zaupanju nekomu (vam, vašemu ponudniku oblaka, vašemu ponudniku baze podatkov). Za notranjo uporabo je to pogosto sprejemljivo. Za regulirane obremenitve (finance, zdravstvo, karkoli, kar je predmet zakonodaje EU o AI) ni.
Kriptografski prejemki to rešijo tako, da je vsako dejanje agenta neodvisno preverljivo. Revizor vam ne mora zaupati. Potrebuje samo vaš javni ključ in sam prejemek.
Prejemek je JSON objekt, ki beleži, kaj je agent storil, podpisan z digitalnim podpisom.
flowchart LR
A[Agent sproži orodje] --> B[Sestavi uporabnino prejemka]
B --> C[Kanoniziraj JSON RFC 8785]
C --> D[SHA-256 zgoščenka]
D --> E[Podpiši z Ed25519]
E --> F[Prejemek z podpisom]
F --> G[Revident preveri brez povezave]
G --> H{Je podpis veljaven?}
H -- yes --> I[Dokaz odpornosti na posege]
H -- no --> J[Prejemek zavrnjen]
Minimalni prejemek izgleda takole:
{
"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..."
}
}
Tri lastnosti opravljajo delo:
Podpis. Prejemek je podpisan vstopno-točkovni agent s pomočjo Ed25519 zasebnega ključa. Kdor ima ustrezni javni ključ, lahko offline preveri podpis. Vsaka sprememba polja velja podpis za neveljaven.
Kanonizirana kodifikacija. Pred podpisovanjem je prejemek serializiran s pomočjo JSON Canonicalization Scheme (JCS, RFC 8785). To zagotavlja, da dve implementaciji, ki ustvarita isti logični prejemek, dajeta bit-po-bit identičen izhod. Brez kanonizacije bi različni JSON serializatorji proizvajali različne podpise za isto vsebino.
Zgoščena veriga. Polje previous_receipt_hash povezuje vsak prejemek s predhodnim. Odstranitev ali prerazporeditev enega prekine vsak naslednji prejemek. Poseg je viden na ravni verige, tudi če so posamezni podpisi obšli.
Skupaj te lastnosti zagotavljajo tri zagotovila:
Za izdelavo prejemka ne potrebujete posebne knjižnice. Kriptografski gradniki so široko dostopni, logika pa je nekaj deset vrstic Pythona.
Vaje v code_samples/18-signed-receipts.ipynb prikazujejo celoten potek. Povzetek:
import json
import hashlib
import base64
from nacl import signing
from jcs import canonicalize # RFC 8785 kanonični 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()}"
# Ustvari ali naloži ključ za podpisovanje (v produkciji shrani v ključavnico ključev)
signing_key = signing.SigningKey.generate()
verify_key = signing_key.verify_key
# Oblikuj vsebino potrdila (še brez podpisa)
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,
}
# Kanoniziraj, zmešaj, podpiši.
canonical_bytes = canonicalize(payload)
message_hash = hashlib.sha256(canonical_bytes).digest()
signature_bytes = signing_key.sign(message_hash).signature
# Pripni strukturiran podpisni objekt.
receipt = {
**payload,
"signature": {
"alg": "EdDSA",
"sig": b64url_nopad(signature_bytes),
"public_key": b64url_nopad(bytes(verify_key)),
},
}
To je celotni postopek podpisovanja. Vaje v zvezku prikazujejo vsak korak.
Preverjanje je obratna operacija:
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:
# Podpis je strukturiran objekt: {"alg", "sig", "public_key"}.
sig_obj = receipt.get("signature")
if not sig_obj or sig_obj.get("alg") != "EdDSA":
return False
# Rekonstruirajte uporabno vsebino, ki je bila dejansko podpisana (vse razen podpisa).
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
Ta funkcija sprejme prejemek in vrne True, če je podpis veljaven, sicer False. Brez klicev v omrežje, brez odvisnosti od storitve, brez zaupanja v tretjo osebo.
Za ogled zaznavanja posega v praksi zvezek prikazuje:
tool_args_hash.To je praktični dokaz, da so prejemki odporni na posege: vsaka sprememba, še tako majhna, prekine podpis.
En sam podpisan prejemek ščiti eno dejanje. Veriga prejemkov ščiti zaporedje.
flowchart LR
R0[Potrdilo 0<br/>geneza] --> R1[Potrdilo 1]
R1 --> R2[Potrdilo 2]
R2 --> R3[Potrdilo 3]
R1 -. previous_receipt_hash .-> R0
R2 -. previous_receipt_hash .-> R1
R3 -. previous_receipt_hash .-> R2
Vsak prejemek beleži zgoščeno vrednost prejšnjega prejemka. Za tiho odstranitev prejemka 2 bi napadalec moral:
previous_receipt_hash prejemka 3 (prekine podpis prejemka 3), ALIČe je zasebni ključ v strojni shrambi ključev in javni ključ objavite z vsakim prejemkom, nobeden od teh napadov ni možen brez odkritja.
Zvezek prikazuje:
previous_receipt_hash vsakega prejemka ujema z dejansko zgoščeno vrednostjo prejšnjega prejemka.Tako ustvarite revizijsko sled, ki jo lahko zunanji revizor preveri brez zaupanja v vas.
Ta del je najpomembnejši v tej lekciji. Prejemki so močni, a imajo omejitve.
Prejemki dokazujejo tri stvari:
Prejemki ne dokazujejo:
policy_id dejansko ocenjena, ali da bi dovolila to dejanje, če bi bila preverjena. Prejemek beleži, kaj je bilo trjeno, ne kaj je bilo izvršeno.Ta meja je pomembna iz dveh razlogov:
Pogosta zmota je domnevati, da “imamo prejemke” pomeni “imamo upravljanje”. Ne pomeni. Prejemki so temelj. Upravljanje je sistem, ki ga gradite na temu temelju.
Točka 3 zgoraj velja svojo ločeno sekcijo: prejemek dejanja pravi “ta ključ je podpisal to vsebino,” nikoli “človek je to odobril”. Za dejanja z visokim tveganjem (vračila denarja, izbrisi, bančna nakazila) okviri upravljanja vedno bolj zahtevajo natanko to manjkajočo izjavo, ki jo je mogoče realizirati z enakimi gradniki, ki ste jih že izdelali v tej lekciji.
Naslednji zvezek code_samples/human-authorization-receipts.ipynb doda drugo vrsto prejemka, human.approval.v1, v isti obliki ovojnice kot prejemki te lekcije (tipiziran naklad podpisan z Ed25519 prek njegove kanonične SHA-256, z objektom signature zunaj podpisanih bajtov). Imenovani odobravalec podpiše celotno kanonično dejanje in njegov digest pred izvršitvijo; prejemek dejanja agenta nosi isti digest dejanja in parent_approval_ref, receipt_hash odobritve, enako konvencijo kot previous_receipt_hash v verigi zgoraj. Ena verify_chain poteka za oba artefakta pod ločenimi registri pripetih ključev (ključi odobravateljev proti ključem agentov), torej je koda skupna, a oblasti nikoli niso.
Lastnost, ki jo to omogoča, izraženo natančno: človek je odobril točno to dejanje, agent pa je izvedel ravno to odobreno dejanje. Objekti zavrnitve v zvezku so tisto, kar lastnost dejansko potrdi, ne le potrdi:
Vsaka napaka zavrne z razlikovalnim razlogom, tako da revizor ob branju zavrnitve vidi, ali je pristojnost zastarala ali se je dejanje spremenilo. Pravilo, ki ga uči zvezek: podpisana odobritev sama po sebi ni pristojnost. Pristojnost obstaja le, če oba prejemka še vedno pripadata istemu kanoničnemu dejanju ob izvršitvi. Pot sobeležnika v istem Internet-Draftu, ki ga ta lekcija sledi (draft-farley-acta-signed-receipts), je standardni vzorec tega modela.
Python koda v tej lekciji je namenoma minimalna, da lahko preberete vsako vrstico in natančno razumete, kaj se dogaja. V produkciji imate dve možnosti:
Gradite neposredno na kriptografskih gradnikih. 50 vrstic, ki ste jih zgoraj videli, zadostuje za veliko primerov uporabe. PyNaCl (Ed25519) in paket jcs (kanonični JSON) so dobro vzdrževani in verificirani knjižnici.
Uporabite knjižnico za produkcijske prejemke. Več odprtokodnih projektov implementira isti vzorec z dodatnimi funkcijami (rotacija ključev, serijsko preverjanje, distribucija JWK seta, integracija s politiko):
draft-farley-acta-signed-receipts, revizija 02), ki je trenutno v postopku standardizacije, z deljenim paketom skladnosti (agent-governance-testvectors), ki ga neodvisne implementacije vzajemno preverjajo za bit-identičen kanonični izhod.protect-mcp (npm) in @veritasacta/verify (npm) zagotavljata implementacijo podpisovanja prejemkov in offline preverjanje v Node okolju, namenjeni ovitju kateregakoli MCP strežnika s protivohunsko revizijsko sledjo, vključno s tokom zadrževalnega sobeležnika, kjer pavzirano dejanje sproži prejemek odobritve, vezan na digest dejanja (WebAuthn-podprt v namiznem toku), isti vzorec odobritvenega prejemka kot zgornji zvezek za avtorizacijo ljudi.pip install nobulex) zagotavlja isti Ed25519 + JCS podpisovalni vzorec v Pythonu z integracijami LangChain in CrewAI, vključno z objavljenimi testnimi vektorji in prispevkom skladnostne preslikave prek OWASP PR #2210.Odločitev med lastno implementacijo in uporabo knjižnice je podobna izbiri med pisanjem svoje JWT knjižnice in uporabo preizkušene: oba pristopa sta razumna; knjižnica prihrani čas in zmanjša površino revizije; pristop od začetka vas sili, da razumete vsak gradnik. Ta lekcija uči pot od začetka, da imate osnovo za katerokoli izbiro.
Preizkusite svoje razumevanje, preden nadaljujete na praktično vajo.
1. Prejemek je podpisan z zasebnim Ed25519 ključem agenta. Revizor ima le javni ključ. Ali lahko revizor prejemek preveri offline?
2. Napadalec spremeni polje policy_id prejemka, da trdi, da ga upravlja bolj permisivna politika. Podpis je bil nad izvirnim nakladom. Kaj se zgodi med preverjanjem?
3. Zakaj prejem vsebuje tool_args_hash in result_hash namesto surovih argumentov in rezultata?
4. Polje previous_receipt_hash povezuje vsak prejem z njegovim predhodnikom. Če napadalec tiho izbriše en prejem sredi verige, kaj postane neveljavno?
5. Prejem se uspešno preveri. Ali to dokazuje, da je bila dejanja agenta pravilna, smiselna ali skladna s politiko?
Odprite code_samples/18-signed-receipts.ipynb in dokončajte vseh štiri razdelke:
Razširjen izziv 1: razširite shemo prejema z dodatnim poljem po lastni izbiri (npr. ID zahteve za sledenje), posodobite kanonično logiko podpisa, da ga vključite, in potrdite, da prejem še vedno prehaja preverjanje. Nato spremenite polje po podpisu in potrdite, da preverjanje ne uspe. To vas prisili razumeti, kako vsak bajt kanoničnega kodiranja prispeva k podpisu.
Razširjen izziv 2: združite SHA-256 hash dveh vaših prejemov (zaporedno združite kanonične bajte v determinističnem vrstnem redu) in vstavite nastali digest kot novo polje v tretji prejem pred podpisom. Preverite, da vsi trije prejemi še vedno preidejo preverjanje. Pravkar ste zgradili dokaz o vključitvi v enem koraku: vsak, ki ima tretji prejem, lahko dokaže, da sta prva dva obstajala v času podpisa, brez razkrivanja vsebine. To je vzorec, ki ga prejmi z selektivno razkritostjo množično uporabljajo (Merkle zaveze, RFC 6962).
Kriptografski prejmi dajo AI agentom revizijsko sled, ki je:
Niso nadomestilo za validacijo vhodov, izvajanje politik ali infrastrukturo identitete. So temelj za te plasti. Ko uvajate agente v regulirane delovne obremenitve, večorganizacijske delovne tokove ali kjer koli, kjer prihodnji revizor ne more vam zaupati, so prejmi način, da revizijska sled ostane poštena.
Najpomembnejše spoznanje: prejmi dokazujejo, kdo je kaj rekel in kdaj. Ne dokazujejo, da je bilo rečeno res ali pravilno. To razliko tesno ohranite. Je razlika med poštenim sistemom izvora in zavajajočim.
Ko ste pripravljeni prestopiti v izvajanje agentov s podpisi prejema v resničnem okolju:
https://your-org.example.com/.well-known/agent-keys.json.Pridružite se Microsoft Foundry Discord, da se srečate z drugimi učenci, se udeležite uradnih ur in dobite odgovore na vprašanja o AI agentih.
Ta lekcija pokriva podpisovanje posameznega prejema in verige z hashi. Enake primitive sestavljajo več naprednih vzorcev, s katerimi se lahko srečate, ko se vaša upravljavska drža razvija:
authorization_*) in po-izvedbene (result_*) polovice z neodvisnimi podpisi, uporabno, kadar odločitev o avtorizaciji in opažen rezultat ustvarita različni strani ali ob različnih časih. To nadgradi format prejema, predstavljen v tej lekciji.result_hash. Realni primeri obremenitev so pogosto bogatejši od samega rezultata klica orodja: premisleki pred odločitvijo (modelna napoved, opcije, dokazila in njihova popolnost, ocena tveganja, veriga odgovornosti, izhod vrata) lahko živijo znotraj obremenitve, zapečatene z enim samim prejemom. To ohranja format prejema minimalen in hkrati omogoča razvoj shem po domenah.signature.alg lahko nosi ML-DSA-65 (NIST po-kvanten podpisni standard), ko boste morali migrirati. Načrtujte prehodno obdobje, ko bodo prejmi podpisani dvojno.Ustvarjanje lokalnih AI agentov
Omejitev odgovornosti: Ta dokument je bil preveden z uporabo AI prevajalske storitve Co-op Translator. Čeprav si prizadevamo za natančnost, vas prosimo, da upoštevate, da avtomatizirani prevodi lahko vsebujejo napake ali netočnosti. Izvirni dokument v njegovem izvirnem jeziku je treba obravnavati kot avtoritativni vir. Za kritične informacije je priporočljiv strokovni človeški prevod. Ne odgovarjamo za morebitna nesporazume ali napačne interpretacije, ki izhajajo iz uporabe tega prevoda.