Vizionați videoclipul lecției: Asigurarea agenților AI cu chitanțe criptografice
(Videoclipul lecției și miniatura vor fi adăugate de echipa de conținut Microsoft după fuziune, urmând modelul lecțiilor 14 / 15.)
Această lecție va acoperi:
După finalizarea acestei lecții, veți ști să:
Imaginați-vă că ați implementat un agent AI pentru Contoso Travel. Agentul citește cererile clienților, apelează un API de zboruri pentru a căuta opțiuni și rezervă locuri în numele clientului. În ultimul trimestru, agentul a procesat 50.000 de rezervări.
Astăzi vine un auditor. El pune o întrebare simplă: „Arată-mi ce a făcut agentul tău.”
Îi înmânați fișierele de jurnal. Auditorul le examinează și pune o întrebare mai dificilă: „Cum știu că aceste jurnale nu au fost editate?”
Aceasta este problema traseului de audit. Cele mai multe implementări ale agenților astăzi se bazează pe:
Nici unul dintre acestea nu poate răspunde la întrebarea auditorului fără să impună ca auditorul să aibă încredere în cineva (dumneavoastră, furnizorul de cloud, vânzătorul bazei de date). Pentru uz intern, această încredere este adesea acceptabilă. Pentru sarcinile reglementate (finanțe, sănătate, orice este supus Regulamentului UE AI), nu este.
Chitanțele criptografice rezolvă această problemă făcând fiecare acțiune a agentului verificabilă independent. Auditorul nu trebuie să aibă încredere în dumneavoastră. Are nevoie doar de cheia dumneavoastră publică și de chitanță în sine.
O chitanță este un obiect JSON care înregistrează ce a făcut un agent, semnat cu o semnătură digitală.
flowchart LR
A[Agentul invocă un instrument] --> B[Construiește încărcătura chitanței]
B --> C[Canonicalizează JSON RFC 8785]
C --> D[Hash SHA-256]
D --> E[Semnează Ed25519]
E --> F[Chitanță cu semnătură]
F --> G[Auditorul verifică offline]
G --> H{Semnătura este validă?}
H -- yes --> I[Dovadă anti-manipulare]
H -- no --> J[Chitanța a fost respinsă]
O chitanță minimală arată așa:
{
"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..."
}
}
Trei proprietăți efectuează treaba:
Semnătura. Chitanța este semnată de poarta agentului folosind o cheie privată Ed25519. Oricine are cheia publică corespunzătoare poate verifica semnătura offline. Modificarea oricărui câmp face semnătura invalidă.
Codificarea canonică. Înainte de semnare, chitanța este serializată folosind Schema de Canonalizare JSON (JCS, RFC 8785). Aceasta asigură că două implementări care produc aceeași chitanță logică produc o ieșire identică la nivel de biți. Fără canonizare, diferiți serializatori JSON ar produce semnături diferite pentru același conținut.
Lanțul de hash. Câmpul previous_receipt_hash leagă fiecare chitanță de cea dinainte. Eliminarea sau reordonarea unei chitanțe rupe fiecare chitanță ulterioară din lanț. Modificările devin vizibile la nivelul lanțului chiar dacă semnăturile individuale sunt ocolite.
Împreună, aceste proprietăți oferă trei garanții:
Nu aveți nevoie de o bibliotecă specială pentru a produce o chitanță. Primitivele criptografice sunt larg disponibile, iar logica este de câteva zeci de linii de cod Python.
Exercițiile practice din code_samples/18-signed-receipts.ipynb parcurg întregul flux. Versiunea sumarizată:
import json
import hashlib
import base64
from nacl import signing
from jcs import canonicalize # JSON canonic RFC 8785
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()}"
# Generează sau încarcă o cheie de semnare (în producție, stochează-o într-un seif de chei)
signing_key = signing.SigningKey.generate()
verify_key = signing_key.verify_key
# Construiește payload-ul chitanței (încă fără semnătură)
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,
}
# Canonicalizează, hash-uiește, semnează.
canonical_bytes = canonicalize(payload)
message_hash = hashlib.sha256(canonical_bytes).digest()
signature_bytes = signing_key.sign(message_hash).signature
# Atașează un obiect de semnătură structurat.
receipt = {
**payload,
"signature": {
"alg": "EdDSA",
"sig": b64url_nopad(signature_bytes),
"public_key": b64url_nopad(bytes(verify_key)),
},
}
Aceasta este întreaga cale de semnare. Exercițiile din notebook prezintă fiecare pas.
Verificarea este operația inversă:
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:
# Semnătura este un obiect structurat: {"alg", "sig", "public_key"}.
sig_obj = receipt.get("signature")
if not sig_obj or sig_obj.get("alg") != "EdDSA":
return False
# Reconstruiește încărcătura care a fost de fapt semnată (totul mai puțin semnătura).
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
Această funcție primește o chitanță și returnează True dacă semnătura este validă, False altfel. Fără apeluri de rețea, fără dependență de servicii, fără încredere într-o terță parte.
Pentru a vedea în acțiune detectarea modificărilor, notebook-ul parcurge:
tool_args_hash.Aceasta este demonstrația practică că chitanțele sunt evidente la modificare: orice modificare, oricât de mică, rupe semnătura.
O singură chitanță semnată protejează o acțiune. Un lanț de chitanțe protejează o secvență.
flowchart LR
R0[Chitanță 0<br/>geneză] --> R1[Chitanță 1]
R1 --> R2[Chitanță 2]
R2 --> R3[Chitanță 3]
R1 -. previous_receipt_hash .-> R0
R2 -. previous_receipt_hash .-> R1
R3 -. previous_receipt_hash .-> R2
Fiecare chitanță înregistrează hash-ul chitanței anterioare. Pentru a elimina silențios chitanța 2, un atacator ar trebui să:
previous_receipt_hash al chitanței 3 (rupe semnătura chitanței 3), SAUDacă cheia privată este într-un seif hardware și publicați cheia publică cu fiecare chitanță, niciun atac nu este fezabil fără detectare.
Notebook-ul parcurge:
previous_receipt_hash al fiecărei chitanțe corespunde cu hash-ul real al chitanței anterioare.Așa produceți un traseu de audit pe care un auditor extern îl poate verifica fără să aibă încredere în dumneavoastră.
Aceasta este cea mai importantă secțiune a lecției. Chitanțele sunt puternice, dar puterea lor are limite.
Chitanțele dovedesc trei lucruri:
Chitanțele NU dovedesc:
policy_id a fost de fapt evaluată sau că ar fi permis această acțiune dacă ar fi fost verificată. Chitanța înregistrează ce s-a pretins, nu ce a fost impus.Această graniță contează din două motive:
O greșeală comună este să presupuneți că „avem chitanțe” înseamnă „suntem guvernați.” Nu înseamnă asta. Chitanțele sunt o fundație. Guvernanța este sistemul pe care îl construiți deasupra.
Punctul 3 de mai sus merită o secțiune proprie: o chitanță de acțiune spune „această cheie a semnat acest conținut,” niciodată „un om a autorizat asta.” Pentru acțiuni cu risc mare (returnări de bani, ștergeri, transferuri bancare), cadrele de guvernanță cer tot mai des exact acea afirmație lipsă, iar ea poate fi produsă cu aceleași primitive construite deja în această lecție.
Notebook-ul ulterior code_samples/human-authorization-receipts.ipynb adaugă un al doilea tip de chitanță, human.approval.v1, în aceeași formă de plic ca chitanțele din lecție (o încărcătură tipizată semnată Ed25519 peste suma canonică SHA-256, cu obiectul signature în afara datelor semnate). Un autorizator numit semnează acțiunea canonică completă și digestul ei înainte de execuție; chitanța acțiunii agentului poartă același digest de acțiune și un parent_approval_ref, hash-ul chitanței de aprobare, aceeași convenție ca previous_receipt_hash din lanțul construit mai sus. O singură funcție verify_chain verifică ambele artefacte sub registrii de chei fixați separați (cheile autorizatorului versus cheile agentului), deci calea codului este comună, dar autoritățile nu.
Proprietatea câștigată, enunțată cu atenție: omul a aprobat această acțiune exactă, iar agentul a executat exact acea acțiune aprobată. Fixture-urile de refuz din notebook sunt ce fac proprietatea reală, nu doar declarată:
Fiecare eșec refuză cu un motiv distinct, astfel încât un auditor care citește un refuz poate spune dacă autoritatea a expirat sau acțiunea executată s-a schimbat. Regula predată în notebook: o aprobare semnată nu este autoritate de una singură. Autoritatea există numai dacă ambele chitanțe încă leagă aceeași acțiune canonică în momentul execuției. Calea co-semnăturii în același Internet-Draft pe care îl urmează această lecție (draft-farley-acta-signed-receipts) este forma standard a acestui model.
Codul Python din această lecție este intenționat minimal pentru ca dumneavoastră să puteți citi fiecare linie și să înțelegeți exact ce se întâmplă. În producție, aveți două opțiuni:
Construiți direct pe primitivele criptografice. Cele 50 de linii pe care le-ați văzut mai sus sunt suficiente pentru multe cazuri de utilizare. PyNaCl (Ed25519) și pachetul jcs (JSON canonic) sunt biblioteci bine întreținute și auditate.
Folosiți o bibliotecă de chitanțe pentru producție. Mai multe proiecte open-source implementează același model cu funcții suplimentare (rotația cheilor, verificarea în lot, distribuția setului JWK, integrarea cu motoare de politici):
draft-farley-acta-signed-receipts, revizia 02) aflat în procesul de standardizare, cu un set comun de conformitate (agent-governance-testvectors) pe care implementările independente îl verifică încrucișat pentru ieșire canonică identică pe biți.protect-mcp (npm) și @veritasacta/verify (npm) oferă o implementare Node pentru semnarea și verificarea offline a chitanțelor, destinată să înfășoare orice server MCP cu un traseu de audit evident la modificări, inclusiv un flux ținut pentru co-semnare în care o acțiune întreruptă emite o chitanță de aprobare legată de digestul acțiunii (sprijinit de WebAuthn în fluxul desktop), același model de chitanță de aprobare ca notebook-ul de autorizare umană de mai sus.pip install nobulex) oferă același model de semnare Ed25519 + JCS în Python cu integrări LangChain și CrewAI, inclusiv vectori de testare de validare încrucișată publicați și o mapare pentru conformitate contribuită prin OWASP PR #2210.Decizia între a vă construi propriul cod și a folosi o bibliotecă reflectă decizia între a scrie propria bibliotecă JWT și a folosi una testată: ambele sunt rezonabile; biblioteca economisește timp și reduce suprafața de audit; abordarea de la zero vă forțează să înțelegeți fiecare primitiv. Această lecție predă calea de la zero pentru a avea fundația pentru orice alegere.
Testați-vă înțelegerea înainte de a trece la exercițiul practic.
1. O chitanță este semnată cu cheia privată Ed25519 a agentului. Auditorul are doar cheia publică. Poate auditorul să verifice chitanța offline?
2. Un atacator modifică câmpul policy_id al unei chitanțe pentru a pretinde că aceasta a fost guvernată de o politică mai permisivă. Semnătura a fost făcută asupra încărcăturii originale. Ce se întâmplă în timpul verificării?
3. De ce chitanța include un tool_args_hash și un result_hash în locul argumentelor și rezultatelor brute?
4. Câmpul previous_receipt_hash leagă fiecare chitanță de precedenta sa. Dacă un atacator șterge în mod silențios o chitanță din mijlocul lanțului, ce devine invalid?
5. O chitanță este verificată cu succes. Dovedește asta că acțiunea agentului a fost corectă, solidă sau conformă cu politica?
Deschide code_samples/18-signed-receipts.ipynb și completează toate cele patru secțiuni:
Provocare suplimentară 1: extinde schema chitanței cu un câmp suplimentar ales de tine (de exemplu, un ID de cerere pentru urmărire), actualizează logica canonică de semnare pentru a-l include și confirmă că chitanța trece verificarea. Apoi modifică câmpul după semnare și confirmă că verificarea eșuează. Acest exercițiu te obligă să înțelegi cum fiecare octet al codificării canonice contribuie la semnătură.
Provocare suplimentară 2: hash-uiește SHA-256 două dintre chitanțele tale împreună (concatenează octeții lor canonici într-o ordine deterministă) și încorporează digestul rezultat ca un câmp nou pe a treia chitanță înainte de semnare. Verifică că toate cele trei chitanțe trec încă verificarea. Tocmai ai construit o dovadă de includere într-un pas: oricine deține a treia chitanță poate demonstra că primele două existau la momentul semnării, fără a dezvălui conținutul lor. Acesta este modelul folosit la scară largă de chitanțele cu dezvăluire selectivă (angajamente Merkle, RFC 6962).
Chitanțele criptografice oferă agenților AI o pistă de audit care este:
Ele nu sunt un substitut pentru validarea intrării, aplicarea politicii sau infrastructura de identitate. Sunt o fundație pentru aceste straturi. Când implementezi agenți în medii reglementate, fluxuri multi-organizaționale sau orice situație în care un auditor viitor nu poate presupune că are încredere în tine, chitanțele sunt modul în care faci pista de audit onestă.
Cel mai important mesaj: chitanțele dovedesc cine a spus ce, când. Nu dovedesc că ceea ce s-a spus este adevărat sau corect. Păstrează această distincție clară. Este diferența dintre un sistem de proveniență onest și unul înșelător.
Când ești gata să treci de la această lecție la implementarea agenților cu semnături pe chitanțe într-un mediu real:
https://your-org.example.com/.well-known/agent-keys.json.Alătură-te Microsoft Foundry Discord pentru a întâlni alți cursanți, a participa la ore de consultanță și a primi răspunsuri pentru întrebările tale despre Agenții AI.
Această lecție acoperă semnarea unei singure chitanțe și lanțuri hash. Aceleași primitive compun mai multe modele avansate pe care le vei întâlni pe măsură ce postura ta de guvernanță se maturizează:
authorization_*) și post-execuție (result_*) cu semnături independente, util când decizia de autorizare și rezultatul observat sunt produse de actori diferiți sau în momente diferite. Aceasta se compune aditiv peste formatul chitanței predat în această lecție.result_hash. Încărcăturile reale sunt adesea mai complexe decât un singur rezultat de apel de unealtă: raționamentul pre-deciție (predicția modelului, opțiunile considerate, dovezile și completitudinea lor, poziția de risc, lanțul de responsabilitate, rezultatul porții) pot locui toate în încărcătură, sigilate de o singură chitanță. Aceasta păstrează formatul chitanței minim, permițând ca schemele încărcăturii să evolueze domeniu cu domeniu.signature.alg poate purta ML-DSA-65 (standardul NIST post-cuantic de semnătură) când ai nevoie de migrare. Planifică o perioadă de tranziție cu chitanțe semnate dual.Declinare a responsabilității: Acest document a fost tradus folosind serviciul de traducere AI Co-op Translator. În timp ce ne străduim pentru acuratețe, vă rugăm să rețineți că traducerile automate pot conține erori sau inexactități. Documentul original în limba sa nativă trebuie considerat sursa autorizată. Pentru informații critice, se recomandă traducerea profesională realizată de un om. Nu ne asumăm responsabilitatea pentru eventualele neînțelegeri sau interpretări greșite care decurg din utilizarea acestei traduceri.