Pogledajte video lekcije: Osiguravanje AI agenata kriptografskim potvrdom
(Video lekcije i sličica bit će dodani od strane Microsoft sadržajnog tima nakon spajanja, u skladu s obrascem lekcija 14 / 15.)
Ova lekcija će pokriti:
Nakon završetka ove lekcije, znat ćete kako:
Zamislite da ste postavili AI agenta za Contoso Travel. Agent čita zahtjeve korisnika, poziva API za letove kako bi pronašao opcije i rezervira sjedala u ime korisnika. Prošli kvartal, agent je obradio 50.000 rezervacija.
Danas dolazi revizor. Postavlja jednostavno pitanje: “Pokažite mi što je vaš agent radio.”
Predajete mu svoje datoteke zapisa. Revizor ih gleda i postavlja teže pitanje: “Kako znam da ti zapisi nisu uređivani?”
Ovo je problem traga revizije. Većina današnjih postavki agenata oslanja se na:
Nitko od njih ne može odgovoriti na revizorsko pitanje bez zahtjeva da revizor nekome vjeruje (vama, vašem cloud provideru, dobavljaču baze podataka). Za internu upotrebu, ta povjerenja su često prihvatljiva. Za regulirane poslove (financije, zdravstvo, bilo što pod EU AI zakonom), nisu.
Kriptografske potvrde to rješavaju tako da svaku radnju agenta čine neovisno provjerljivom. Revizor ne mora vjerovati vama. Treba mu samo vaš javni ključ i sama potvrda.
Potvrda je JSON objekt koji bilježi što je agent učinio, potpisan digitalnim potpisom.
flowchart LR
A[Agent pokreće alat] --> B[Izradi korisnički teret potvrde]
B --> C[Kanonizira JSON RFC 8785]
C --> D[SHA-256 hash]
D --> E[Ed25519 potpis]
E --> F[Potvrda s potpisom]
F --> G[Revizor potvrđuje offline]
G --> H{Potpis valjan?}
H -- yes --> I[Dokaz otporan na manipulacije]
H -- no --> J[Potvrda odbijena]
Minimalna potvrda izgleda ovako:
{
"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 svojstva rade posao:
Potpis. Potvrdu potpisuje agentov gateway koristeći Ed25519 privatni ključ. Svako tko ima odgovarajući javni ključ može offline verifikovati potpis. Izmjena bilo kojeg polja poništava potpis.
Kanonsko kodiranje. Prije potpisivanja potvrda je serijalizirana korištenjem JSON Kanonskog Šema (JCS, RFC 8785). To osigurava da dvije implementacije koje proizvode isti logički zapis daju bitno identičan izlaz. Bez kanonskog kodiranja, različiti JSON serijalizatori dali bi različite potpise za isti sadržaj.
Hashed lančanje. Polje previous_receipt_hash povezuje svaku potvrdu s prethodnom. Uklanjanje ili preuređivanje potvrde prekida sve potvrde koje slijede. Manipulacija postaje vidljiva na razini lanca čak i ako se pojedinačni potpisi zaobiđu.
Zajedno ova svojstva daju tri jamstva:
Nije vam potrebna posebna biblioteka za proizvodnju potvrde. Kriptografski primitivci su široko dostupni, a logika je samo nekoliko desetaka linija Python koda.
Praktične vježbe u code_samples/18-signed-receipts.ipynb prolaze kroz cijeli tok. Sažetak verzije:
import json
import hashlib
import base64
from nacl import signing
from jcs import canonicalize # RFC 8785 kanonski 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()}"
# Generiraj ili učitaj ključ za potpisivanje (u proizvodnji pohrani u sef za ključeve)
signing_key = signing.SigningKey.generate()
verify_key = signing_key.verify_key
# Izradi korisnički zapis (još bez potpisa)
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, heširaj, potpiši.
canonical_bytes = canonicalize(payload)
message_hash = hashlib.sha256(canonical_bytes).digest()
signature_bytes = signing_key.sign(message_hash).signature
# Priloži strukturirani objekt potpisa.
receipt = {
**payload,
"signature": {
"alg": "EdDSA",
"sig": b64url_nopad(signature_bytes),
"public_key": b64url_nopad(bytes(verify_key)),
},
}
To je cijeli proces potpisivanja. Vježbe u bilježnici vode kroz svaki korak.
Verifikacija je obrnuta 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:
# Potpis je strukturirani objekt: {"alg", "sig", "public_key"}.
sig_obj = receipt.get("signature")
if not sig_obj or sig_obj.get("alg") != "EdDSA":
return False
# Rekonstruirajte korisni podatak koji je zapravo potpisan (sve osim potpisa).
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
Ova funkcija prima potvrdu i vraća True ako je potpis valjan, False inače. Nema mrežnog poziva, nema ovisnosti o usluzi, ne treba se vjerovati nikome trećem.
Da biste vidjeli detekciju manipulacije u akciji, bilježnica prolazi kroz:
tool_args_hash.Ovo je praktični dokaz da su potvrde otporne na manipulaciju: svaka izmjena, koliko god mala bila, prekida potpis.
Jedna potpisana potvrda štiti jednu radnju. Lanac potvrda štiti niz radnji.
flowchart LR
R0[Potvrda 0<br/>postanak] --> R1[Potvrda 1]
R1 --> R2[Potvrda 2]
R2 --> R3[Potvrda 3]
R1 -. previous_receipt_hash .-> R0
R2 -. previous_receipt_hash .-> R1
R3 -. previous_receipt_hash .-> R2
Svaka potvrda zapisuje hash prethodne potvrde. Da bi se tiho uklonila potvrda 2, napadač bi morao ili:
previous_receipt_hash u potvrdi 3 (time bi potpis potvrde 3 bio nevažeći), ILIAko je privatni ključ u hardverskom sejfu i javni ključ objavljujete sa svakom potvrdom, niti jedan od tih napada nije izvediv bez detekcije.
Bilježnica prolazi kroz:
previous_receipt_hash svake potvrde odgovara stvarnom hešu prethodne potvrde.Ovo je način na koji stvarate trag revizije koji vanjski revizor može provjeriti bez da vam mora vjerovati.
Ovo je najvažniji dio ove lekcije. Potvrde su moćne, ali njihova snaga ima granice.
Potvrde dokazuju tri stvari:
Potvrde ne dokazuju:
policy_id stvarno evaluirana, ili da bi dozvolila radnju ako bi se provjeravala. Potvrda bilježi što je tvrdnja, ne što je provedeno.Ova granica je važna iz dva razloga:
Česta je pogreška pretpostaviti da “imamo potvrde” znači “upravljamo.” Ne znači. Potvrde su temelj. Upravljanje je sustav koji gradite na njemu.
Točka 3 gore zaslužuje poseban odjeljak: potvrda radnje kaže “ovaj ključ je potpisao ovaj sadržaj,” nikada “čovjek je odobrio ovo.” Za radnje visokog rizika (refundacije, brisanja, transferi novca), okviri upravljanja sve više zahtijevaju upravo tu nedostajuću izjavu, a može se proizvesti istim primitivcima koje ste već napravili u ovoj lekciji.
Sljedeća bilježnica code_samples/human-authorization-receipts.ipynb dodaje drugu vrstu potvrde, human.approval.v1, u istom obliku omotnice kao potvrde u lekciji (tipizirani teret potpisan Ed25519 nad kanonskim SHA-256, s objektom signature izvan potpisanih bajtova). Imenovani odobravatelj potpisuje potpunu kanonsku radnju i njen sažetak prije izvršenja; potvrda radnje agenta nosi isti sažetak radnje i referencu parent_approval_ref, receipt_hash odobrenja, istu konvenciju kao previous_receipt_hash u lancu koji ste izgradili gore. Jedan verify_chain izvršava provjeru oba artefakta pod odvojenim registrima piniranih ključeva (ključevi odobravatelja vs ključevi agenata), tako da je put koda zajednički ali ovlasti nikada nisu.
Svojstvo koje ovo donosi, pažljivo izraženo: čovjek je odobrio upravo ovu radnju, a agent ju je točno i izvršio. Odbijanja u bilježnici su ono što ovo svojstvo čini stvarnim, a ne samo tvrdnjom:
Svaki neuspjeh odbija s različitim razlogom, tako da revizor koji čita odbijanje može razlikovati je li ovlast zastarjela ili je radnja promijenjena. Pravilo koje uči bilježnica: potpisano odobrenje samo po sebi nije ovlast. Ovlast postoji samo ako obje potvrde još uvijek vežu na istu kanonsku radnju u vrijeme izvršenja. Put su-potpisivanja u istom Internet-Nacrtu na kojem se zasniva ova lekcija (draft-farley-acta-signed-receipts) je standardni oblik ovog obrasca.
Python kod u ovoj lekciji je namjerno minimalan kako biste mogli pročitati svaki redak i točno razumjeti što se događa. U produkciji imate dvije opcije:
Gradite direktno na kriptografskim primitivima. 50 redaka koje ste vidjeli gore su dovoljni za mnoge slučajeve upotrebe. PyNaCl (Ed25519) i paket jcs (kanonski JSON) su dobro održavane i revidirane biblioteke.
Koristite produkcijsku biblioteku za potvrde. Nekoliko open-source projekata implementira isti obrazac s dodatnim značajkama (rotacija ključeva, grupna verifikacija, distribucija JWK seta, integracija s policy engine-ima):
draft-farley-acta-signed-receipts, revizija 02) koji je trenutno u procesu standardizacije, s dijeljenim konformacijskim paketom (agent-governance-testvectors) kojim se neovisne implementacije međusobno provjeravaju radi identične kanonske izlaznosti.protect-mcp (npm) i @veritasacta/verify (npm) pružaju implementaciju potpisivanja i offline verifikacije potvrda u Node.js, namijenjenu omatanju svakog MCP servera s tragom revizije otpornim na manipulaciju, uključujući tok za ko-potpisivanje u kojem zaustavljena radnja emitira potvrdu odobrenja povezanu s sažetkom radnje (WebAuthn podržano u desktop toku), isti obrazac potvrde odobrenja kao i bilježnica za autorizaciju čovjeka gore.pip install nobulex) pruža isti obrazac potpisivanja Ed25519 + JCS u Pythonu s LangChain i CrewAI integracijama, uključujući objavljene testne vektore za unakrsnu validaciju i mapiranje usklađenosti pridonijeto putem OWASP PR #2210.Odluka između izgradnje vlastitog rješenja i korištenja biblioteke je slična odluci između pisanja vlastite JWT biblioteke i korištenja testirane: oba su razumna; biblioteka štedi vrijeme i smanjuje površinu revizije; pristup od početka prisiljava vas da razumijete svaki primitiv. Ova lekcija uči taj put od početka tako da imate temelj za oba izbora.
Testirajte svoje razumijevanje prije prelaska na praktičnu vježbu.
1. Potvrda se potpisuje privatnim Ed25519 ključem agenta. Revizor ima samo javni ključ. Može li revizor verificirati potvrdu offline?
2. Napadač mijenja polje policy_id u potvrdi kako bi tvrdio da je bila podložna permisivnijoj politici. Potpis je bio nad izvornim teretom. Što se događa tijekom verifikacije?
3. Zašto račun sadrži tool_args_hash i result_hash umjesto sirovih argumenata i rezultata?
4. Polje previous_receipt_hash povezuje svaki račun sa svojim prethodnikom. Ako napadač tiho obriše jedan račun iz sredine lanca, što postaje nevažeće?
5. Račun se uspješno verificira. Dokazuje li to da je postupak agenta bio ispravan, valjan ili u skladu s politikom?
Otvorite code_samples/18-signed-receipts.ipynb i završite sva četiri dijela:
Izazov 1: proširite shemu računa dodatnim poljem po vlastitom izboru (na primjer, ID zahtjeva za praćenje), ažurirajte logiku kanonskog potpisivanja da ga uključi, te potvrdite da račun i dalje uspješno prolazi provjeru. Zatim izmijenite polje nakon potpisivanja i potvrdite da verifikacija ne uspijeva. Ovo vas prisiljava da razumijete kako svaki bajt kanonskog kodiranja doprinosi potpisu.
Izazov 2: Spojite SHA-256 hashom dva svoja računa zajedno (spojite njihove kanonske bajtove u determinističkom redoslijedu) i ugradite dobiveni digest kao novo polje na treći račun prije potpisivanja. Provjerite da sva tri računa i dalje prolaze. Upravo ste napravili dokaz uključivanja u jednom koraku: bilo tko tko ima treći račun može dokazati da su prvi dva postojala u vrijeme potpisivanja, bez potrebe da otkriva njihov sadržaj. Ovaj obrazac koriste računi s selektivnim otkrivanjem u velikim sustavima (Merklejeva stabla, RFC 6962).
Kriptografski računi daju AI agentima revizijski trag koji je:
Oni nisu zamjena za validaciju unosa, provođenje politika ili infrastrukturu identiteta. Oni su temelj za te slojeve. Kada implementirate agente u reguliranim okruženjima, višestrukim organizacijama ili u bilo kojem okruženju gdje se ne može pretpostaviti da vam budući revizor vjeruje, računi su način da se revizijski trag učini iskrenim.
Najvažnija poruka: računi dokazuju tko je što rekao i kada. Ne dokazuju da je ono što je rečeno istina ili ispravno. Čuvajte tu razliku čvrsto. To je razlika između iskrenog sustava podrijetla i obmanjujućeg.
Kad budete spremni prijeći s ove lekcije na implementaciju agenata s potpisanim računima u stvarnom okruženju:
https://your-org.example.com/.well-known/agent-keys.json.Pridružite se Microsoft Foundry Discordu da se povežete s drugim učenicima, sudjelujete u uredu za pitanja i dobijete odgovore na pitanja o AI agentima.
Ova lekcija pokriva potpisivanje pojedinačnih računa i nizove s hash-lancom. Isti primitivci se slažu u nekoliko naprednijih obrazaca koje možete susresti kako vaš upravljački sustav sazrijeva:
authorization_*) i postizvršni (result_*) dio s neovisnim potpisima, korisno kada su odluka o autorizaciji i promatrani rezultat generirani od različitih aktera ili u različito vrijeme. Ovo nadograđuje obrazac računa prikazan u ovoj lekciji.result_hash. Pravi korisni podaci su često bogatiji nego rezultat jednog poziva alatu: predodluka (predviđanje modela, razmotrene opcije, dokazi i njihova potpunost, rizik, lanac odgovornosti, ishod prolaza) mogu svi biti unutar korisne informacije, zatvoreni jednim računom. Ovo održava format računa minimalnim dok dopušta evoluciju shema po domeni.signature.alg može nositi ML-DSA-65 (NIST post-kvantni standard potpisa) kad vam treba migracija. Planirajte prijelazno razdoblje kad su računi dvostruko potpisani.Napomena: Ovaj dokument je preveden korištenjem AI prevoditeljskog servisa Co-op Translator. Iako težimo točnosti, imajte na umu da automatski prijevodi mogu sadržavati greške ili netočnosti. Izvorni dokument na izvornom jeziku treba smatrati autoritativnim izvorom. Za važne informacije preporuča se profesionalni ljudski prijevod. Nismo odgovorni za bilo kakva nesporazumevanja ili pogrešne interpretacije koje proizlaze iz korištenja ovog prijevoda.