Nézze meg az óravideót: AI ügynökök védelme kriptográfiai bizonylatokkal
(Az óravideót és a bélyegképet a Microsoft tartalomcsapata adja hozzá az összefésülés után, az 14/15. lecke mintájának megfelelően.)
Ez az óra a következő témákat fogja érinteni:
Az óra elvégzése után tudni fogja, hogyan:
Képzelje el, hogy telepített egy AI ügynököt a Contoso Travel számára. Az ügynök olvassa az ügyfél kéréseit, meghív egy járatok API-t az opciók lekérdezéséhez, és lefoglal helyeket az ügyfél nevében. Az előző negyedévben az ügynök 50 000 foglalást dolgozott fel.
Ma megérkezik egy auditor. Egy egyszerű kérdést tesz fel: “Mutassa meg, mit csinált az ügynöke.”
Átadja a naplófájlokat. Az auditor megnézi azokat, majd egy nehezebb kérdést tesz fel: “Honnan tudom, hogy ezeket a naplókat nem szerkesztették?”
Ez az audit nyomvonali probléma. A mai ügynök telepítések többsége a következőkre támaszkodik:
Ezek egyike sem tud választ adni az auditor kérdésére anélkül, hogy az auditor valakiben megbízzon (Önben, a felhőszolgáltatóban vagy az adatbázis szállítójában). Belső használatra ez az elfogadható megbízhatóság gyakran elegendő. Szabályozott munkafolyamatokhoz (pénzügy, egészségügy, minden, amire az EU AI irányelv vonatkozik) nem az.
A kriptográfiai bizonylatok ezt úgy oldják meg, hogy minden egyes ügynöki művelet függetlenül ellenőrizhetővé válik. Az auditor nem Önben bízik meg, csak a nyilvános kulcsban és magában a bizonylatban.
Egy bizonylat egy JSON objektum, amely rögzíti, mit tett az ügynök, digitális aláírással ellátva.
flowchart LR
A[Az ügynök eszközt hív meg] --> B[Nyugta adattermék összeállítása]
B --> C[JSON kanonizálás RFC 8785 szerint]
C --> E[Ed25519 aláírás a kanonikus bájtokon]
E --> F[Aláírt nyugta]
F --> G[Az auditor offline módon ellenőrzi]
G --> H{Az aláírás érvényes?}
H -- yes --> I[Változtatás-ellenálló bizonyíték]
H -- no --> J[Nyugta elutasítva]
Egy minimális bizonylat így néz ki:
{
"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..."
}
}
Három tulajdonság végzi a munkát:
Az aláírás. A bizonylatot az ügynök átjárója írja alá Ed25519 privát kulccsal. Bárki, aki rendelkezik a megfelelő nyilvános kulccsal, offline ellenőrizheti az aláírást. A mezők bármilyen manipulációja érvénytelenné teszi az aláírást.
Kanonikus kódolás. Aláírás előtt a bizonylatot a JSON Canonicalization Scheme (JCS, RFC 8785) szerint szerializálják. Ez biztosítja, hogy két implementáció, amely ugyanazt az értelmi bizonylatot állítja elő, bájtazonos outputot generáljon. Kanonikalizáció nélkül különböző JSON szerializálók eltérő aláírásokat állítanának elő azonos tartalomhoz.
Hash-láncolás. A previous_receipt_hash mező összekapcsolja minden bizonylatot az előzővel. Egy bizonylat eltávolítása vagy átrendezése megszakítja az utána következő minden bizonylatot. A manipuláció a láncnál is láthatóvá válik, még ha az egyedi aláírásokat meg is kerülik.
Ezek a tulajdonságok három garanciát nyújtanak:
Nincs szükség külön könyvtárra a bizonylat készítéséhez. A kriptográfiai primitívek széles körben elérhetők, és a logika néhány tucat sor Python.
A gyakorlati gyakorlatok a code_samples/18-signed-receipts.ipynb fájlban lépésről lépésre végigvezetik a teljes folyamatot. A rövid összefoglaló:
import json
import hashlib
import base64
from nacl import signing
from jcs import canonicalize # RFC 8785 kanonikus 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()}"
# Aláíró kulcs generálása vagy betöltése (éles környezetben tárolja kulcstárban)
signing_key = signing.SigningKey.generate()
verify_key = signing_key.verify_key
# A blokk nyugtázási tartalom összeállítása (még nincs aláírás)
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,
}
# A JCS bájtokat kanonizálja és aláírja közvetlenül. A PureEdDSA belsőleg hashel.
canonical_bytes = canonicalize(payload)
signature_bytes = signing_key.sign(canonical_bytes).signature
# Struktúrált aláírási objektum csatolása.
receipt = {
**payload,
"signature": {
"alg": "EdDSA",
"sig": b64url_nopad(signature_bytes),
"public_key": b64url_nopad(bytes(verify_key)),
},
}
Ez a teljes aláírási folyamat. A jegyzetfüzet lépésenként végigvezeti minden részét.
Az ellenőrzés az ellentétes művelet:
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:
# Az aláírás egy strukturált objektum: {"alg", "sig", "public_key"}.
sig_obj = receipt.get("signature")
if not sig_obj or sig_obj.get("alg") != "EdDSA":
return False
# Állítsuk vissza a ténylegesen aláírt tartalmat (minden, az aláírást kivéve).
payload = {k: v for k, v in receipt.items() if k != "signature"}
canonical_bytes = canonicalize(payload)
try:
verify_key = signing.VerifyKey(b64url_decode(sig_obj["public_key"]))
verify_key.verify(canonical_bytes, b64url_decode(sig_obj["sig"]))
return True
except BadSignatureError:
return False
Ez a függvény kap egy bizonylatot, és True-t ad vissza, ha az aláírás érvényes, ellenkező esetben False-t. Nincs hálózati hívás, nincs szolgáltatásfüggőség, nem szükséges megbízni harmadik félben.
A manipuláció észlelésének megtekintéséhez a jegyzetfüzet bemutatja:
tool_args_hash mezőben.Ez a gyakorlati bemutató, hogy a bizonylatok manipulációt láthatóvá tesznek: bármilyen módosítás, akár kicsi is, megszakítja az aláírást.
Egyetlen aláírt bizonylat egy műveletet véd. A bizonylatok láncolata egy szekvenciát véd.
flowchart LR
R0[Nyugta 0<br/>kezdete] --> R1[Nyugta 1]
R1 --> R2[Nyugta 2]
R2 --> R3[Nyugta 3]
R1 -. previous_receipt_hash .-> R0
R2 -. previous_receipt_hash .-> R1
R3 -. previous_receipt_hash .-> R2
Minden bizonylat rögzíti az előző bizonylat hash-ét. Egy támadó ahhoz, hogy a 2. bizonylatot csendben eltávolítsa, vagy:
previous_receipt_hash mezőjét (ezzel megszakad a 3. bizonylat aláírása), VAGYHa a privát kulcs hardveres kulcstárolóban van, és közzéteszi a nyilvános kulcsot minden bizonylattal, egyik támadás sem kivitelezhető észrevétel nélkül.
A jegyzetfüzet bemutatja:
previous_receipt_hash megegyezik az előző bizonylat valódi hash-ével.Így készíthet audit nyomvonalat, amelyet egy külső auditor ellenőrizhet anélkül, hogy Önben bíznia kellene.
Ez a lecke legfontosabb része. A bizonylatok erőteljesek, de korlátok között.
A bizonylatok három dolgot bizonyítanak:
A bizonylatok NEM bizonyítanak:
policy_id-ban hivatkozott szabályzatot ténylegesen alkalmazták-e, vagy hogy engedélyezte volna-e ezt a műveletet, ha ellenőrizték volna. A bizonylat azt rögzíti, amit állítottak, nem azt, amit végrehajtottak.Ez a határvonal két okból fontos:
Gyakori tévedés azt hinni, hogy “van bizonylatunk” azt jelenti, hogy “megfelelünk.” Ez nem igaz. A bizonylatok alapot adnak. A szabályozás az a rendszer, amelyet erre építünk.
A fenti 3. pont megérdemel egy külön szakaszt: egy művelet bizonylat azt mondja, “ez a kulcs írta alá ezt a tartalmat,” sosem azt, hogy “egy ember engedélyezte ezt.” Magas kockázatú műveleteknél (visszatérítések, törlések, átutalások) a szabályozási keretrendszerek egyre inkább kifejezetten ezt a hiányzó igazolást követelik meg, amely előállítható ugyanazokkal az eszközökkel, amelyeket ebben a leckében már használt.
A folytató jegyzetfüzet, a code_samples/human-authorization-receipts.ipynb egy második típusú bizonylatot, a human.approval.v1-et ad hozzá, amely ugyanabban a boríték formában van, mint a lecke bizonylatai (tipizált csomag, amelyet Ed25519 ír alá kanonikus JCS bájtokon, az aláírás objektum a bájtokon kívül). Egy névvel ellátott jóváhagyó írja alá a teljes kanonikus műveletet és annak hash-ét a végrehajtás előtt; az ügynök műveleti bizonylata hordozza a ugyanazt a műveleti hash-t és egy parent_approval_ref-et, a jóváhagyás bizonylatának receipt_hash-ét, ugyanazzal a konvencióval, mint a láncban az előző bizonylat hash-e, previous_receipt_hash. Egy verify_chain mindkét artefaktumot ellenőrzi külön állított kulcsnyilvántartások alatt (jóváhagyó kulcsok vs ügynök kulcsok), így a kódút közös, de a hatóságok soha nem.
A tulajdonság, amelyet így kapunk, gondosan megfogalmazva: az ember jóváhagyta ezt az adott műveletet, és az ügynök pontosan ezt az engedélyezett műveletet hajtotta végre. A jegyzetfüzet elutasítási eset tesztjei teszik megalapozottá ezt a tulajdonságot:
Minden hiba elutasítással jár, egyedi okkal, így az auditor meg tudja különböztetni, hogy lejárt-e a hatóság, vagy változott-e a végrehajtott művelet. A jegyzetfüzet által tanított szabály: egy aláírt jóváhagyás nem hatóság önmagában. A hatóság csak akkor áll fenn, ha mindkét bizonylat ugyanahhoz a kanonikus művelethez kötött a végrehajtás idején. Az emberi jóváhagyás bizonylata oktatási kompozíció, amelyet ez az óra definiál, nem a draft-farley-acta-signed-receipts által definiált bizonylattípus.
Ennek az órának a Python kódja szándékosan minimális, hogy minden sort elolvashasson és pontosan értse, mi történik. Éles környezetben két lehetősége van:
Közvetlenül a kriptográfiai primitívekre építkezik. A fent látott 50 sor sok esetben elegendő. A PyNaCl (Ed25519) és a jcs csomag (kanonikus JSON) jól karbantartott és auditált könyvtárak.
Használ egy éles bizonylat könyvtárat. Több nyílt forráskódú projekt valósítja meg ugyanazt a mintát további funkciókkal (kulcscsere, tömeges ellenőrzés, JWK készlet terjesztés, integráció a szabályzat motorokkal):
draft-farley-acta-signed-receipts, 02. revízió). A lecke lapos oktató bizonylata különbözik a tervezet {payload, signature} borítékától és nem konform megvalósításként jelenik meg. A tervezet közzétesz egy megosztott konformancia csomagot (agent-governance-testvectors) a formátum célzott megvalósításaihoz.protect-mcp (npm) és @veritasacta/verify (npm) csomagok Node-alapú megvalósítást kínálnak bizonylat aláíráshoz és offline ellenőrzéshez, céljuk MCP szerverek tamper-evidens audit nyomvonalának becsomagolása, beleértve egy tárgyalt co-sign (együtt aláírás) folyamatot is, ahol egy szüneteltetett művelet jóváhagyási bizonylatot bocsát ki, amely a műveleti hash-hez kötött (desktop folyamatban WebAuthn-támogatással), ugyanaz a jóváhagyási bizonylat minta, mint az emberi jóváhagyás jegyzetfüzetben.pip install nobulex) ugyanazt az Ed25519 + JCS aláírási mintát nyújtja Pythonban LangChain és CrewAI integrációkkal, publikált keresztezési tesztvektorokkal és megfelelés térképezéssel, amelyet a OWASP PR #2210 járult hozzá.Az, hogy sajátot készít vagy könyvtárat használ, hasonló döntés, mint JWT könyvtár esetén: mindkettő ésszerű; a könyvtár időt spórol és csökkenti az audit felületet; a nulláról építkezés arra kényszerít, hogy minden primitívát megértsen. Ez az óra az alapoktól induló utat tanítja, hogy mindkét választás alapját ismerje.
Tesztelje megértését, mielőtt a gyakorlati feladathoz lép.
1. Egy bizonylatot az ügynök Ed25519 privát kulcsával írnak alá. Az auditor csak a nyilvános kulccsal rendelkezik. Tudja az auditor offline ellenőrizni a bizonylatot?
2. Egy támadó módosítja a bizonylat policy_id mezőjét, azt állítva, hogy egy engedékenyebb szabályzat irányította. Az aláírás a eredeti adatokon alapult. Mi történik az ellenőrzés során?
3. Miért tartalmaz a blokk tool_args_hash és result_hash mezőket a nyers argumentumok és eredmény helyett?
4. A previous_receipt_hash mező minden blokkot az elődjéhez köt. Ha egy támadó csendben töröl egy blokkot egy lánc közepéről, mi lesz érvénytelen?
5. Egy blokk tisztán ellenőrzött. Vajon ez bizonyítja, hogy az ügynök művelete helyes, megalapozott vagy megfelel a szabályzatnak?
Nyissa meg a code_samples/18-signed-receipts.ipynb fájlt és fejezze be a négy részt:
Haladó feladat 1: Bővítse a blokk sémáját egy saját választott mezővel (például nyomkövetési kérésazonosítóval), frissítse a kanonikus aláírási logikát, hogy ezt is tartalmazza, és győződjön meg róla, hogy a blokk továbbra is helyesen ellenőrződik. Ezután módosítsa a mezőt aláírás után, és győződjön meg róla, hogy az ellenőrzés megbukik. Ez arra készteti, hogy megértse, hogyan járul hozzá a kanonikus kódolás minden bájtja az aláíráshoz.
Haladó feladat 2: Készítsen SHA-256-at két blokkjára együttesen (kanonikus bájtjaikat determinisztikus sorrendben összefűzve), majd ágyazza be a keletkezett digest-et egy harmadik blokk új mezőjeként aláírás előtt. Ellenőrizze, hogy mindhárom blokk továbbra is helyesen ellenőrződik. Ezzel egy egylépéses befogadási bizonyítékot épített: aki a harmadik blokkot birtokolja, igazolhatja, hogy az első kettő létezett az aláírás időpontjában anélkül, hogy azok tartalmát felfedné. Ez az a minta, amelyet a kiválasztó közzétételi blokkok nagy léptékben használnak (Merkle-elköteleződések, RFC 6962).
A kriptográfiai blokkok olyan audit nyomot adnak az AI ügynököknek, amely:
Nem helyettesítik a bemeneti ellenőrzést, szabályzatvégrehajtást vagy identitásinfrastruktúrát. Ezek ezek alapját képezik. Amikor ügynököket telepít szabályozott környezetbe, több szervezetes munkafolyamatokba vagy bármilyen olyan helyzetbe, ahol a jövőbeni auditor nem feltételezhetően bízik önben, a blokkok teszik az audit nyomot őszintévé.
A legfontosabb tanulság: a blokkok bizonyítják, ki, mit, mikor mondott. Nem bizonyítják, hogy az elmondott igaz vagy helyes volt. Ezt a különbséget szorosan tartsa szem előtt. Ez a különbség egy becsületes eredettörténeti rendszer és egy megtévesztő között.
Amikor készen áll arra, hogy a leckéből továbblépve éles környezetben telepítsen blokk-aláírásos ügynököket:
https://your-org.example.com/.well-known/agent-keys.json.Csatlakozzon a Microsoft Foundry Discord közösséghez, találkozzon más tanulókkal, vegyen részt hivatalos fogadóórákon, és kapja meg AI ügynökök kérdéseire a válaszokat.
Ez a lecke egyetlen blokk aláírását és hash láncolt sorozatokat mutat be. Ugyanazok a primitívek számos fejlettebb mintává állnak össze, amelyekkel találkozhat, ahogy irányítási környezete fejlődik:
authorization_*) és utó-végrehajtási (result_*) részekre független aláírásokkal, ami hasznos, ha az engedélyezési döntést és az észlelt eredményt külön szereplők vagy időpontok állítják elő. Ez összerakható a leckében tanult blokk formátumra.result_hash-ban ad meg. A valós adatok gyakran gazdagabbak, mint egyetlen eszközhívás eredménye: döntés előtti gondolkodás (modell-előrejelzés, fontolóra vett opciók, bizonyíték és annak teljessége, kockázati helyzet, elszámoltathatósági lánc, döntő kapu eredmény) mind beleférnek az adathordozóba, amelyet egy blokk zár le. Ez minimalizálja a blokk formátumát, miközben az adatsémák egyes területek szerint fejlődhetnek.signature.alg mező tartalmazhatja az ML-DSA-65-öt (a NIST poszt-kvantum aláírási szabványát), amikor szükséges az átállás. Tervezzen átmeneti időszakot, amikor a blokkok két aláírással rendelkeznek.Jogi nyilatkozat: Ez a dokumentum az AI fordítási szolgáltatás, a Co-op Translator segítségével készült. Bár az pontosságra törekszünk, kérjük, vegye figyelembe, hogy az automatikus fordítások hibákat vagy pontatlanságokat tartalmazhatnak. Az eredeti dokumentum az anyanyelvén tekintendő hiteles forrásnak. Fontos információk esetén professzionális emberi fordítást javasolunk. Nem vállalunk felelősséget semmilyen félreértésért vagy téves értelmezésért, amely ebből a fordításból ered.