Watch the lesson video: Säkerställa AI-agenter med kryptografiska kvitton
(Lektionsvideo och miniatyrbild kommer att läggas till av Microsofts innehållsteam efter sammanslagning, i enlighet med lektionsmönstret för lektion 14 / 15.)
Den här lektionen kommer att täcka:
Efter att ha genomfört denna lektion kommer du att kunna:
Föreställ dig att du har driftsatt en AI-agent för Contoso Travel. Agenten läser kundförfrågningar, anropar en flyg-API för att söka efter alternativ och bokar platser för kundens räkning. Förra kvartalet hanterade agenten 50 000 bokningar.
Idag anländer en revisor. De ställer en enkel fråga: “Visa mig vad din agent gjorde.”
Du lämnar över dina loggfiler. Revisorn tittar på dem och ställer den svårare frågan: “Hur vet jag att dessa loggar inte har redigerats?”
Detta är problemet med revisionsspår. De flesta agentutplaceringar idag förlitar sig på:
Ingen av dessa kan svara på revisorns fråga utan att kräva att revisorn litar på någon (dig, din molnleverantör, din databasmjukvara). För internt bruk är det ofta acceptabelt. För reglerade arbetsbelastningar (finans, sjukvård, allt som omfattas av EU:s AI-förordning) är det det inte.
Kryptografiska kvitton löser detta genom att göra varje agents åtgärd oberoende verifierbar. Revisorn behöver inte lita på dig. De behöver bara din offentliga nyckel och själva kvittot.
Ett kvitto är ett JSON-objekt som registrerar vad en agent gjorde, signerat med en digital signatur.
flowchart LR
A[Agent anropar ett verktyg] --> B[Skapa kvitto-payload]
B --> C[Kanonisera JSON RFC 8785]
C --> D[SHA-256 hash]
D --> E[Ed25519 signera]
E --> F[Kvitto med signatur]
F --> G[Revisor verifierar offline]
G --> H{Signatur giltig?}
H -- ja --> I[Felfri bevisning]
H -- nej --> J[Kvitto avvisat]
Ett minimalt kvitto ser ut så här:
{
"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 gör jobbet:
Signaturen. Kvittot signeras av agentens gateway med hjälp av en Ed25519-privatnyckel. Den som har tillgång till motsvarande offentliga nyckel kan verifiera signaturen offline. Manipulering av något fält gör signaturen ogiltig.
Kanonisk kodning. Innan signering serialiseras kvittot med JSON Canonicalization Scheme (JCS, RFC 8785). Detta säkerställer att två implementationer som producerar samma logiska kvitto ger identisk byte-utdata. Utan kanonisering skulle olika JSON-serialiserare skapa olika signaturer för samma innehåll.
Hash-kedjning. Fältet previous_receipt_hash länkar varje kvitto till det föregående. Att ta bort eller ändra ordningen på ett kvitto bryter varje efterföljande kvitto i kedjan. Manipulation blir synlig på kedjenivå även om individuella signaturer skulle kringgås.
Tillsammans ger dessa egenskaper tre garantier:
Du behöver inget specialbibliotek för att skapa ett kvitto. De kryptografiska primitiva funktionerna är allmänt tillgängliga och logiken är några tiotals rader Python.
De praktiska övningarna i code_samples/18-signed-receipts.ipynb visar hela flödet. Sammanfattningsvis:
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()}"
# Generera eller ladda en signeringsnyckel (i produktion, lagra i en nyckelvalv)
signing_key = signing.SigningKey.generate()
verify_key = signing_key.verify_key
# Bygg kvitto-payloaden (ingen signatur ännu)
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,
}
# Kanonifiera, hash, signera.
canonical_bytes = canonicalize(payload)
message_hash = hashlib.sha256(canonical_bytes).digest()
signature_bytes = signing_key.sign(message_hash).signature
# Bifoga ett strukturerat signaturobjekt.
receipt = {
**payload,
"signature": {
"alg": "EdDSA",
"sig": b64url_nopad(signature_bytes),
"public_key": b64url_nopad(bytes(verify_key)),
},
}
Det är hela signeringspipeline. Övningarna i anteckningsboken går igenom varje steg.
Verifiering är den omvända operationen:
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 är ett strukturerat objekt: {"alg", "sig", "public_key"}.
sig_obj = receipt.get("signature")
if not sig_obj or sig_obj.get("alg") != "EdDSA":
return False
# Återskapa nyttolasten som faktiskt signerades (allt utom 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
Denna funktion tar ett kvitto och returnerar True om signaturen är giltig, annars False. Ingen nätverksanrop, ingen beroende av tjänst, inget behov av att lita på någon tredje part.
För att se hur manipulationsdetektion fungerar går anteckningsboken igenom:
tool_args_hash.Detta är den praktiska demonstrationen att kvitton är manipulationssäkra: varje ändring, hur liten som helst, bryter signaturen.
Ett enskilt signerat kvitto skyddar en åtgärd. En kedja av kvitton skyddar en sekvens.
flowchart LR
R0[Kvitto 0<br/>ursprung] --> R1[Kvitto 1]
R1 --> R2[Kvitto 2]
R2 --> R3[Kvitto 3]
R1 -. previous_receipt_hash .-> R0
R2 -. previous_receipt_hash .-> R1
R3 -. previous_receipt_hash .-> R2
Varje kvitto registrerar hashen av föregående kvitto. För att tyst radera kvitto 2 måste en angripare antingen:
previous_receipt_hash i kvitto 3 (bryter signaturen för kvitto 3), ELLEROm den privata nyckeln finns i ett hårdvarunyckelvalv och du publicerar den publika nyckeln med varje kvitto är ingen av attackerna möjlig utan upptäckt.
Anteckningsboken går igenom:
previous_receipt_hash matchar den faktiska hashen av föregående kvitto.Så här producerar du ett revisionsspår som en extern revisor kan verifiera utan att lita på dig.
Detta är den viktigaste delen av lektionen. Kvitton är kraftfulla men deras makt är begränsad.
Kvitton bevisar tre saker:
Kvitton bevisar INTE:
policy_id faktiskt utvärderades, eller att den skulle ha tillåtit denna åtgärd om den kontrollerades. Kvittot registrerar vad som påstås, inte vad som upprätthölls.Denna gräns är viktig av två skäl:
Ett vanligt misstag är att anta att “vi har kvitton” betyder “vi är styrda”. Det gör det inte. Kvitton är en grund. Styrning är systemet du bygger ovanpå.
Python-koden i denna lektion är avsiktligt minimal så att du kan läsa varje rad och förstå exakt vad som händer. I produktion har du två alternativ:
Bygg direkt på de kryptografiska primitiva funktionerna. De 50 rader du såg ovan räcker för många användningsfall. PyNaCl (Ed25519) och paketet jcs (kanonisk JSON) är väl underhållna och granskade bibliotek.
Använd ett produktionsbibliotek för kvitton. Flera open source-projekt implementerar samma mönster med extra funktioner (nyckelrotation, batch-verifiering, JWK Set-distribution, integration med policymotorer):
draft-farley-acta-signed-receipts) som för närvarande är i standardiseringsprocess.protect-mcp (npm) och @veritasacta/verify (npm) erbjuder en Node-baserad implementering av kvitto-signering och offline-verifiering, avsedda att omsluta vilken MCP-server som helst med ett manipulationssäkert revisionsspår.Beslutet mellan att göra själv och att använda ett bibliotek liknar valet mellan att skriva ditt eget JWT-bibliotek och använda ett testat: båda är rimliga; biblioteket sparar tid och minskar granskningsyta; självbygget tvingar dig att förstå varje primitiv. Denna lektion lär ut självbygget så att du har grunden för båda valen.
Testa din förståelse innan du går vidare till övningen.
1. Ett kvitto signeras med agentens privata Ed25519-nyckel. Revisorn har endast den publika nyckeln. Kan revisorn verifiera kvittot offline?
2. En angripare ändrar fältet policy_id i ett kvitto för att påstå att det styrdes av en mer tillåtande policy. Signaturen var över den ursprungliga payloaden. Vad händer vid verifiering?
3. Varför inkluderar kvittot en tool_args_hash och result_hash istället för de råa argumenten och resultatet?
4. Fältet previous_receipt_hash länkar varje kvitto till dess föregångare. Om en angripare tyst raderar ett kvitto från mitten av kedjan, vad blir ogiltigt?
5. Ett kvitto verifieras utan fel. Bevisar det att agentens åtgärd var korrekt, giltig eller policykompliant?
Öppna code_samples/18-signed-receipts.ipynb och slutför alla fyra sektionerna:
Utmaning 1: Utöka kvittoschemat med ett extra fält du väljer (t.ex. ett förfrågnings-ID för spårning), uppdatera den kanoniska signeringslogiken för att inkludera det och bekräfta att kvittot fortfarande går igenom verifieringen utan problem. Ändra sedan fältet efter signering och verifiera att verifieringen misslyckas. Detta tvingar dig att förstå hur varje byte i den kanoniska kodningen bidrar till signaturen. Stretch-utmaning 2: SHA-256-hash två av dina kvitton tillsammans (konkatenera deras kanoniska bytes i en deterministisk ordning) och bädda in den resulterande digesten som ett nytt fält på ett tredje kvitto innan du signerar det. Verifiera att alla tre kvitton fortfarande går att rundresa. Du har just byggt ett enstegs inklusionsbevis: vem som helst som har det tredje kvittot kan bevisa att de två första existerade när det signerades, utan att behöva avslöja deras innehåll. Detta är mönstret som kvitton med selektiv avslöjande använder i stor skala (Merkle-åtaganden, RFC 6962).
Kryptografiska kvitton ger AI-agenturer en revisionsspår som är:
De är inte en ersättning för inmatningsvalidering, policyimplementering eller identitetsinfrastruktur. De är en grund för dessa lager. När du distribuerar agenter i reglerade arbetsbelastningar, flervariabla arbetsflöden eller någon miljö där en framtida revisor inte kan antas lita på dig, är kvitton hur du gör revisionsspåret ärligt.
Den viktigaste slutsatsen: kvitton bevisar vem som sa vad, när. De bevisar inte att vad som sagts var sant eller rätt. Håll den skillnaden tydlig. Det är skillnaden mellan ett ärligt provenienssystem och ett vilseledande.
När du är redo att gå vidare från denna lektion till att distribuera kvitto-signerade agenter i en verklig miljö:
https://your-org.example.com/.well-known/agent-keys.json.Gå med i Microsoft Foundry Discord för att möta andra lärande, delta i kontorstid och få svar på dina frågor om AI-agenter.
Denna lektion täcker enkel kvittosignering och hash-kedjade sekvenser. Samma primitiva bygger ihop sig till flera mer avancerade mönster du kan stöta på när din styrningspostur mognar:
authorization_*) och efterutförande (result_*) halvdelar med oberoende signaturer, användbara när auktoriseringsbeslutet och det observerade resultatet produceras av olika aktörer eller vid olika tillfällen. Detta bygger på kvittoformatet som lärdes i denna lektion.result_hash. Verkliga nyttolaster är ofta rikare än ett enda verktygsanropsresultat: förbeslutsresonemang (modellprediktion, betraktade alternativ, bevis och dess fullständighet, riskpostur, ansvarskedja, grindutfall) kan alla bo inuti nyttolasten, förseglade av ett enda kvitto. Detta håller kvittoformatet minimalt samtidigt som nyttolasscheman kan utvecklas domän för domän.signature.alg kan bära ML-DSA-65 (NIST:s postkvant-signaturstandard) när du behöver migrera. Planera för en övergångsperiod där kvitton är dubbelsignerade.Building Computer Use Agents (CUA)
(Bestäms av kursansvariga)
Ansvarsfriskrivning: Detta dokument har översatts med hjälp av AI-översättningstjänsten Co-op Translator. Även om vi strävar efter noggrannhet, var vänlig notera att automatiska översättningar kan innehålla fel eller brister. Det ursprungliga dokumentet på dess modersmål bör betraktas som den auktoritativa källan. För kritisk information rekommenderas professionell mänsklig översättning. Vi ansvarar inte för några missförstånd eller feltolkningar som uppstår till följd av användningen av denna översättning.