Se leksjonsvideoen: Sikring av AI-agenter med kryptografiske kvitteringer
(Leksjonsvideo og miniatyrbilde skal legges til av Microsofts innholdsteam etter sammenslåing, i samsvar med mønsteret for leksjon 14 / 15.)
Denne leksjonen vil dekke:
Etter å ha fullført denne leksjonen vil du vite hvordan du:
Tenk deg at du har satt i drift en AI-agent for Contoso Travel. Agenten leser kundeforespørsler, kaller en flights-API for å søke etter alternativer, og reserverer seter på vegne av kunden. Forrige kvartal behandlet agenten 50 000 bestillinger.
I dag kommer en revisor. De stiller et enkelt spørsmål: “Vis meg hva agenten din har gjort.”
Du gir dem loggfilene dine. Revisoren ser på dem og stiller det vanskeligere spørsmålet: “Hvordan vet jeg at disse loggene ikke er blitt redigert?”
Dette er revisjonssporproblemet. De fleste agentdistribusjoner i dag stoler på:
Ingen av disse kan svare revisors spørsmål uten at revisor må stole på noen (deg, skyløsningen, databaseleverandøren). For internt bruk er denne tilliten ofte akseptabel. For regulerte arbeidsbelastninger (finans, helse, alt underlagt EU AI-loven) er det ikke det.
Kryptografiske kvitteringer løser dette ved å gjøre hver agenthandling uavhengig verifiserbar. Revisor trenger ikke stole på deg. De trenger kun din offentlige nøkkel og kvitteringen selv.
En kvittering er et JSON-objekt som registrerer hva en agent gjorde, signert med en digital signatur.
flowchart LR
A[Agenten påkaller et verktøy] --> B[Bygg kvitteringsdata]
B --> C[Kanonsialiser JSON RFC 8785]
C --> D[SHA-256 hash]
D --> E[Ed25519 signerer]
E --> F[Kvittering med signatur]
F --> G[Revisor verifiserer offline]
G --> H{Signatur gyldig?}
H -- ja --> I[Bevis som viser manipulasjon]
H -- nei --> J[Avvist kvittering]
En minimal kvittering ser slik ut:
{
"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 egenskaper gjør jobben:
Signaturen. Kvitteringen signeres av agentens gateway ved bruk av en Ed25519-privatnøkkel. Enhver med tilsvarende offentlig nøkkel kan verifisere signaturen offline. Endring i noen felt ugyldiggjør signaturen.
Kanonisk koding. Før signering serialiseres kvitteringen med JSON Canonicalization Scheme (JCS, RFC 8785). Dette sikrer at to implementasjoner som produserer samme logiske kvittering gir byte-identisk utdata. Uten kanonisering ville ulike JSON-serialiserere produsere forskjellige signaturer for samme innhold.
Hash-kjedning. Feltet previous_receipt_hash kobler hver kvittering til den foregående. Fjerning eller omordning av en kvittering bryter alle kvitteringer som kommer etter. Manipulering blir synlig på kjedenivå selv om enkelte signaturer omgås.
Disse egenskapene gir til sammen tre garantier:
Du trenger ikke et spesielt bibliotek for å produsere en kvittering. De kryptografiske primitivene er bredt tilgjengelige og logikken er noen dusin linjer Python.
De praktiske øvelsene i code_samples/18-signed-receipts.ipynb går gjennom hele prosessen. Her er en oppsummering:
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 last inn en signeringsnøkkel (i produksjon, lagres i en nøkkellager)
signing_key = signing.SigningKey.generate()
verify_key = signing_key.verify_key
# Bygg kvitteringsdata (ingen signatur ennå)
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, hasj, signer.
canonical_bytes = canonicalize(payload)
message_hash = hashlib.sha256(canonical_bytes).digest()
signature_bytes = signing_key.sign(message_hash).signature
# Legg ved et strukturert signaturobjekt.
receipt = {
**payload,
"signature": {
"alg": "EdDSA",
"sig": b64url_nopad(signature_bytes),
"public_key": b64url_nopad(bytes(verify_key)),
},
}
Dette er hele signeringsprosessen. Øvelsene i notatblokken dekker hvert steg.
Verifisering er den motsatte operasjonen:
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 strukturert objekt: {"alg", "sig", "public_key"}.
sig_obj = receipt.get("signature")
if not sig_obj or sig_obj.get("alg") != "EdDSA":
return False
# Gjenoppbygg nyttelasten som faktisk ble signert (alt unntatt 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 funksjonen tar en kvittering og returnerer True hvis signaturen er gyldig, False ellers. Ingen nettverkskall, ingen tjenesteavhengighet, ingen tillit kreves til tredjepart.
For å se manipulering i praksis, går notatblokken gjennom:
tool_args_hash.Dette er den praktiske demonstrasjonen at kvitteringer er manipulasjonsavdekkende: enhver endring, uansett hvor liten, bryter signaturen.
En enkelt signert kvittering beskytter én handling. En kjede av kvitteringer beskytter en sekvens.
flowchart LR
R0[Mottak 0<br/>genesis] --> R1[Mottak 1]
R1 --> R2[Mottak 2]
R2 --> R3[Mottak 3]
R1 -. previous_receipt_hash .-> R0
R2 -. previous_receipt_hash .-> R1
R3 -. previous_receipt_hash .-> R2
Hver kvittering registrerer hashen av kvitteringen før den. For å fjerne kvittering 2 stille, må en angriper enten:
previous_receipt_hash i kvittering 3 (bryter signaturen til kvittering 3), ELLERHvis den private nøkkelen er i et hardware key vault og du publiserer den offentlige nøkkelen med hver kvittering, er ingen av disse angrepene gjennomførbare uten å bli oppdaget.
Notatblokken går gjennom:
previous_receipt_hash matcher den faktiske hashen til forrige kvittering.Slik produserer du et revisjonsspor en ekstern revisor kan verifisere uten å måtte stole på deg.
Dette er den viktigste delen av leksjonen. Kvitteringer er kraftfulle, men kraften deres er begrenset.
Kvitteringer beviser tre ting:
Kvitteringer BEVISER IKKE:
policy_id faktisk ble evaluert, eller at den ville tillatt handlingen hvis sjekket. Kvitteringen registrerer hva som ble påstått, ikke hva som ble håndhevet.Dette skillet er viktig av to grunner:
En vanlig feil er å anta at “vi har kvitteringer” betyr “vi har styring.” Det gjør det ikke. Kvitteringer er fundamentet. Styring er systemet du bygger oppå.
Python-koden i denne leksjonen er bevisst minimal for at du skal kunne lese hver linje og forstå nøyaktig hva som skjer. I produksjon har du to alternativer:
Bygg direkte på de kryptografiske primitivene. De 50 linjene du så over er tilstrekkelige for mange brukstilfeller. PyNaCl (Ed25519) og jcs-pakken (kanonisk JSON) er godt vedlikeholdte og reviderte biblioteker.
Bruk et produksjonsbibliotek for kvitteringer. Flere open-source-prosjekter implementerer samme mønster med tillegg (nøkkelrotasjon, batch-verifisering, distribusjon av JWK-sett, integrasjon med policy-motorer):
draft-farley-acta-signed-receipts) som er under standardiseringsprosess.protect-mcp (npm) og @veritasacta/verify (npm) pakker gir en Node-basert implementasjon for signering og offline verifisering av kvitteringer, ment for å omslutte enhver MCP-server med et manipulasjonsavdekkende revisjonsspor.Valget mellom å lage din egen og bruke et bibliotek ligner valget mellom å skrive ditt eget JWT-bibliotek og bruke et testet: begge er rimelige; biblioteket sparer tid og reduserer revisjonsoverflaten; fra-scratch-tilnærmingen tvinger deg til å forstå hver primitiv. Denne leksjonen lærer deg fra-scratch-tilnærmingen slik at du har grunnlaget for begge valg.
Test forståelsen din før du går videre til øvelsen.
1. En kvittering er signert med agentens private Ed25519-nøkkel. Revisor har bare den offentlige nøkkelen. Kan revisor verifisere kvitteringen offline?
2. En angriper endrer policy_id-feltet i en kvittering for å påstå at den ble styrt av en mer tillatende policy. Signaturen var over den opprinnelige nyttelasten. Hva skjer ved verifisering?
3. Hvorfor inkluderer kvitteringen tool_args_hash og result_hash i stedet for rå argumenter og resultat?
4. Feltet previous_receipt_hash knytter hver kvittering til forgjengeren. Hvis en angriper stille fjerner en kvittering midt i kjeden, hva blir ugyldig?
5. En kvittering verifiseres luktfritt. Beviser det at agentens handling var korrekt, holdbar, eller i samsvar med policy?
Åpne code_samples/18-signed-receipts.ipynb og fullfør alle fire seksjoner:
Ekstra utfordring 1: utvid kvitteringsskjemaet med et tillegg av ditt eget valg (for eksempel en forespørsels-ID for sporing), oppdater den kanoniske signeringslogikken til å inkludere det, og bekreft at kvitteringen fortsatt går igjennom verifisering. Endre deretter feltet etter signering og bekreft at verifiseringen feiler. Dette tvinger deg til å forstå hvordan hver byte i den kanoniske kodingen bidrar til signaturen. Stretch challenge 2: SHA-256-hash to av kvitteringene dine sammen (konsatenere deres kanoniske bytes i en deterministisk rekkefølge) og legg inn den resulterende digesten som et nytt felt på en tredje kvittering før du signerer den. Verifiser at alle tre kvitteringene fremdeles kan rundreise. Du har nettopp bygget et ett-trinns inklusjonsbevis: hvem som helst som har den tredje kvitteringen kan bevise at de to første eksisterte på tidspunktet den ble signert, uten å måtte avsløre innholdet deres. Dette er mønsteret som selektive-discolosure kvitteringer bruker i stor skala (Merkle-commitments, RFC 6962).
Kryptografiske kvitteringer gir AI-agenter en revisjonsspor som er:
De er ikke en erstatning for inndata-validering, policyhåndhevelse eller identitetsinfrastruktur. De er et fundament for disse lagene. Når du distribuerer agenter i regulerte arbeidsbelastninger, flerorganisasjons arbeidsflyter, eller andre settinger hvor en fremtidig revisor ikke kan antas å stole på deg, er kvitteringer hvordan du gjør revisjonssporet ærlig.
Det viktigste å ta med seg: kvitteringer beviser hvem som sa hva, når. De beviser ikke at det som ble sagt var sant eller riktig. Hold det skillet stramt. Det er forskjellen mellom et ærlig provenienssystem og et villedende.
Når du er klar til å gå videre fra denne leksjonen til å distribuere kvittering-signerte agenter i et reelt miljø:
https://your-org.example.com/.well-known/agent-keys.json.Bli med i Microsoft Foundry Discord for å møte andre lærende, delta på kontortimer, og få svar på spørsmål om AI-agenter.
Denne leksjonen dekker enkeltkvitterings-signering og hash-kjedede sekvenser. De samme primitivene komponerer flere mer avanserte mønstre du kan møte når styringsposturen modnes:
authorization_*) og post-eksekvering (result_*) halvdeler med uavhengige signaturer, nyttig når autorisasjonsbeslutningen og det observerte resultatet produseres av forskjellige aktører eller til ulike tider. Dette bygger additivt videre på kvitteringsformatet lært i denne leksjonen.result_hash. Virkelige nyttelaster er ofte rikere enn et enkelt verktøys kall-resultat: forhåndsbeslutningsresonnement (modellprediksjon, vurderte alternativer, bevis og deres fullstendighet, risikopostur, ansvarskjede, gateutfall) kan alle leve inni nyttelasten, lukket av en enkelt kvittering. Dette holder kvitteringsformatet minimalt mens nyttelastskjemaer kan utvikle seg domene-for-domene.signature.alg feltet kan bære ML-DSA-65 (NIST sin post-kvantem signaturstandard) når du trenger å migrere. Planlegg en overgangsperiode hvor kvitteringer er dobbelt-signert.Building Computer Use Agents (CUA)
(Bestemmes av læreplan-vedlikeholdere)
Ansvarsfraskrivelse: Dette dokumentet er oversatt ved hjelp av AI-oversettelsestjenesten Co-op Translator. Selv om vi streber etter nøyaktighet, vær oppmerksom på at automatiske oversettelser kan inneholde feil eller unøyaktigheter. Det opprinnelige dokumentet på originalspråket skal betraktes som den autoritative kilden. For kritisk informasjon anbefales profesjonell menneskelig oversettelse. Vi er ikke ansvarlige for eventuelle misforståelser eller feiltolkninger som oppstår ved bruk av denne oversettelsen.