Se lektionens video: Sikring af AI-agenter med kryptografiske kvitteringer
(Lektionsvideo og miniaturebillede tilføjes af Microsofts indholdsteam efter sammenfletning, i overensstemmelse med mønsteret for lektion 14 / 15.)
Denne lektion vil dække:
Efter at have gennemført denne lektion vil du vide, hvordan du:
Forestil dig, at du har sat en AI-agent i drift for Contoso Travel. Agenten læser kundeanmodninger, kalder en fly-API for at finde muligheder og booker pladser på kundens vegne. I sidste kvartal behandlede agenten 50.000 bookinger.
I dag ankommer en revisor. De stiller et enkelt spørgsmål: “Vis mig, hvad din agent gjorde.”
Du giver dine logfiler. Revisoren ser på dem og spørger det sværere spørgsmål: “Hvordan ved jeg, at disse logs ikke er redigerede?”
Dette er problemet med revisionsspor. De fleste agentimplementeringer i dag baserer sig på:
Ingen af disse kan besvare revisorens spørgsmål uden, at revisoren er nødt til at stole på nogen (dig, din cloud-udbyder, din databaseleverandør). Til intern brug er den tillid ofte acceptabel. For regulerede arbejdsbelastninger (finans, sundhedsvæsen, alt omfattet af EU’s AI-lov) er den det ikke.
Kryptografiske kvitteringer løser dette ved at gøre hver agenthandling uafhængigt verificerbar. Revisoren behøver ikke at stole på dig. De behøver kun din offentlige nøgle og selve kvitteringen.
En kvittering er et JSON-objekt, der registrerer, hvad en agent gjorde, underskrevet med en digital signatur.
flowchart LR
A[Agent påkalder et værktøj] --> B[Byg kvitteringsindhold]
B --> C[Kanonicér JSON RFC 8785]
C --> D[SHA-256 hash]
D --> E[Ed25519 signér]
E --> F[Kvittering med signatur]
F --> G[Revisor verificerer offline]
G --> H{Signatur gyldig?}
H -- ja --> I[Manipulationssikkert bevis]
H -- nej --> J[Kvittering afvist]
En minimal kvittering ser sådan ud:
{
"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..."
}
}
Tre egenskaber udfører arbejdet:
Signaturen. Kvitteringen er underskrevet af agentens gateway med en Ed25519-privatnøgle. Enhver med den tilhørende offentlige nøgle kan verificere signaturen offline. Manipulation med ethvert felt ugyldiggør signaturen.
Kanonisk kodning. Før underskrivelse serialiseres kvitteringen med JSON Canonicalization Scheme (JCS, RFC 8785). Dette sikrer, at to implementeringer, som producerer samme logiske kvittering, producerer byte-identisk output. Uden kanonisering ville forskellige JSON-serialisatorer producere forskellige signaturer for samme indhold.
Hash-kædning. Feltet previous_receipt_hash linker hver kvittering til den foregående. Fjernelse eller omlægning af en kvittering bryder hver kvittering, der kom efter. Manipulation bliver synlig på kædeniveau, selv hvis individuelle signaturer omgås.
Sammen giver disse egenskaber tre garantier:
Du behøver ikke et særligt bibliotek for at producere en kvittering. De kryptografiske primitive findes bredt, og logikken er blot nogle få dusin linjer Python.
De praktiske øvelser i code_samples/18-signed-receipts.ipynb gennemgår hele forløbet. Kortversionen:
import json
import hashlib
import base64
from nacl import signing
from jcs import canonicalize # RFC 8785 kanonisk 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()}"
# Generer eller indlæs en signeringsnøgle (i produktion, gem i et nøglelager)
signing_key = signing.SigningKey.generate()
verify_key = signing_key.verify_key
# Byg kvitterings-payloaden (ingen signatur endnu)
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,
}
# Kanoniser, hash, signér.
canonical_bytes = canonicalize(payload)
message_hash = hashlib.sha256(canonical_bytes).digest()
signature_bytes = signing_key.sign(message_hash).signature
# Vedhæft et struktureret signaturobjekt.
receipt = {
**payload,
"signature": {
"alg": "EdDSA",
"sig": b64url_nopad(signature_bytes),
"public_key": b64url_nopad(bytes(verify_key)),
},
}
Det er hele underskrivningsrøret. Øvelserne i notebooken går trin for trin igennem.
Verificering er den inverse operation:
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:
# Signaturen er et struktureret objekt: {"alg", "sig", "public_key"}.
sig_obj = receipt.get("signature")
if not sig_obj or sig_obj.get("alg") != "EdDSA":
return False
# Genskab payload'en, der faktisk blev underskrevet (alt undtagen signaturen).
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
Denne funktion tager en kvittering og returnerer True hvis signaturen er gyldig, False ellers. Intet netværkskald, ingen serviceafhængighed, ingen tillid nødvendig til tredjepart.
For at se opdagelse af manipulation i praksis vejleder notebooken i:
tool_args_hash.Dette er den praktiske demonstration af, at kvitteringer er manipulationssikre: enhver ændring, hvor lille den end er, bryder signaturen.
En enkelt underskrevet kvittering beskytter en handling. En kæde af kvitteringer beskytter en sekvens.
flowchart LR
R0[Kvittering 0<br/>oprindelse] --> R1[Kvittering 1]
R1 --> R2[Kvittering 2]
R2 --> R3[Kvittering 3]
R1 -. previous_receipt_hash .-> R0
R2 -. previous_receipt_hash .-> R1
R3 -. previous_receipt_hash .-> R2
Hver kvittering registrerer hashen af kvitteringen før den. For at fjerne kvittering 2 uden at blive opdaget skulle en angriber enten:
previous_receipt_hash-felt (bryder kvittering 3’s signatur), ELLERHvis den private nøgle ligger i en hardware-nøgleboks, og du offentliggør den offentlige nøgle med hver kvittering, er ingen af angrebene mulige uden opdagelse.
Notebooken gennemgår:
previous_receipt_hash matcher den faktiske hash af den forrige kvittering.Sådan producerer du et revisionsspor, som en ekstern revisor kan verificere uden at stole på dig.
Dette er det vigtigste afsnit i lektionen. Kvitteringer er stærke, men deres kraft er begrænset.
Kvitteringer beviser tre ting:
Kvitteringer beviser IKKE:
policy_id rent faktisk blev evalueret, eller at den ville have tilladt handlingen, hvis den blev kontrolleret. Kvitteringen registrerer, hvad der blev hævdet, ikke hvad der blev håndhævet.Denne grænse er vigtig af to grunde:
En almindelig fejltagelse er at antage, at “vi har kvitteringer” betyder “vi er styret.” Det gør de ikke. Kvitteringer er fundamentet. Styring er systemet, du bygger ovenpå.
Python-koden i denne lektion er bevidst minimal, så du kan læse hver linje og forstå nøjagtigt, hvad der sker. I produktion har du to muligheder:
Byg direkte på de kryptografiske primitive. De 50 linjer ovenfor er tilstrækkelige for mange brugsscenarier. PyNaCl (Ed25519) og jcs-pakken (kanonisk JSON) er velvedligeholdte og reviderede biblioteker.
Brug et produktionskvitteringsbibliotek. Flere open source-projekter implementerer det samme mønster med ekstra funktioner (nøglerotation, batchverificering, JWK Set-distribution, integration med politikmotorer):
draft-farley-acta-signed-receipts) som er under standardiseringsproces.protect-mcp (npm) og @veritasacta/verify (npm) tilbyder en Node-baseret implementering af kvitteringssignering og offline-verificering, beregnet til at pakke enhver MCP-server med et manipulationssikkert revisionsspor.pip install nobulex) tilbyder samme Ed25519 + JCS underskrivningsmønster i Python med integration til LangChain og CrewAI, inklusiv offentliggjorte krydsvalideringstestvektorer og et overholdelseskort bidraget via OWASP PR #2210.Valget mellem at kode selv og bruge et bibliotek svarer til valget mellem at skrive sit eget JWT-bibliotek og bruge et testet: begge er rimelige; biblioteket sparer tid og mindsker revisionsfladen; selvskrevet tvinger dig til at forstå hver primitive. Denne lektion lærer selvskrevet vejen, så du har grundlaget for begge valg.
Test din forståelse inden du går videre til øvelsen.
1. En kvittering er underskrevet med agentens private Ed25519-nøgle. Revisor har kun den offentlige nøgle. Kan revisor verificere kvitteringen offline?
2. En angriber ændrer policy_id-feltet i en kvittering for at hævde, at den blev styret af en mere lempelig politik. Signaturen dækkede den oprindelige payload. Hvad sker ved verificering?
3. Hvorfor indeholder kvitteringen en tool_args_hash og en result_hash i stedet for de rå argumenter og resultater?
4. Feltet previous_receipt_hash linker hver kvittering til sin forgænger. Hvis en angriber stille sletter en kvittering midt i en kæde, hvad bliver ugyldigt?
5. En kvittering verificeres korrekt. Beviser det, at agentens handling var korrekt, solid eller i overensstemmelse med politik?
Åbn code_samples/18-signed-receipts.ipynb og gennemfør alle fire sektioner:
Stretch udfordring 2: SHA-256-hash to af dine kvitteringer sammen (kæd deres kanoniske bytes sammen i en deterministisk rækkefølge) og indlejre det resulterende digest som et nyt felt på en tredje kvittering før signeringen. Bekræft at alle tre kvitteringer stadig kan gennemføres. Du har netop bygget et inklusionsbevis i ét trin: enhver, der har den tredje kvittering, kan bevise, at de to første eksisterede på det tidspunkt, den blev signeret, uden at afsløre deres indhold. Dette er det mønster, som selective-disclosure kvitteringer bruger i stor skala (Merkle-committments, RFC 6962).
Kryptografiske kvitteringer giver AI-agenter en revisionssti, der er:
De er ikke en erstatning for inputvalidering, politikhåndhævelse eller identitetsinfrastruktur. De er fundamentet for disse lag. Når du implementerer agenter i regulerede arbejdsbelastninger, arbejdsflow med flere organisationer eller i enhver sammenhæng, hvor en fremtidig revisor ikke kan antages at have tillid til dig, er kvitteringer den måde, hvorpå du sikrer en ærlig revisionssti.
Den vigtigste pointe: kvitteringer beviser, hvem der sagde hvad, hvornår. De beviser ikke, at det sagde var sandt eller korrekt. Hold denne sondring skarpt. Det er forskellen mellem et ærligt oprindelsessystem og et misvisende.
Når du er klar til at gå videre fra denne lektion til at implementere kvitteringssignerede agenter i et reelt miljø:
https://your-org.example.com/.well-known/agent-keys.json.Deltag i Microsoft Foundry Discord for at møde andre elever, deltage i kontortid og få svar på dine AI Agent-spørgsmål.
Denne lektion dækker enkeltkvitteringssignering og hash-kædede sekvenser. De samme primitive komponenter sammensætter flere mere avancerede mønstre, som du kan støde på, efterhånden som din styringsholdning modnes:
authorization_*) og post-eksekvering (result_*) halvdele med uafhængige signaturer, nyttigt når autorisationsbeslutningen og det observerede resultat produceres af forskellige aktører eller på forskellige tidspunkter. Dette bygger additivt oven på kvitteringsformatet, som er lært i denne lektion.result_hash. Virkelige payloads er ofte rigere end et enkelt værktøjskalds resultat: præ-beslutningsræsonnement (modelprediktion, overvejede muligheder, bevis og dets fuldstændighed, risikoposition, ansvarskæde, portresultat) kan alle bo inden i payloaden, forseglet af en enkelt kvittering. Dette holder kvitteringsformatet minimalt, mens payloadskemaer kan udvikle sig domæne-for-domæne.signature.alg kan indeholde ML-DSA-65 (NIST post-kvante signaturstandard), når du skal migrere. Planlæg en overgangsperiode, hvor kvitteringer er dobbelt-signeret.Building Computer Use Agents (CUA)
(Bestemmes af studieordningsvedligeholdere)
Ansvarsfraskrivelse: Dette dokument er blevet oversat ved hjælp af AI-oversættelsestjenesten Co-op Translator. Selvom vi bestræber os på nøjagtighed, skal du være opmærksom på, at automatiserede oversættelser kan indeholde fejl eller unøjagtigheder. Det originale dokument på dets oprindelige sprog bør betragtes som den autoritative kilde. For kritisk information anbefales professionel menneskelig oversættelse. Vi påtager os intet ansvar for misforståelser eller fejltolkninger, der opstår som følge af brugen af denne oversættelse.