Urmărește 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, în conformitate cu modelul lecției 14 / 15.)
Această lecție va acoperi:
După ce parcurgi această lecție, vei ști cum să:
Imaginează-ți că ai 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 sosește un auditor. El pune o întrebare simplă: “Arată-mi ce a făcut agentul tău.”
Îi dai fișierele tale jurnal. Auditorul le privește și pune o întrebare mai dificilă: “Cum știu că aceste jurnale nu au fost editate?”
Aceasta este problema urmei de audit. Majoritatea implementărilor de agenți din prezent se bazează pe:
Niciunul dintre acestea nu poate răspunde întrebării auditorului fără ca auditorul să aibă încredere în cineva (în tine, furnizorul tău de cloud, vânzătorul bazei de date). Pentru utilizarea internă, această încredere este adesea acceptabilă. Pentru sarcinile reglementate (finanțe, sănătate, orice subiect al Regulamentului UE privind AI), nu este.
Chitanțele criptografice rezolvă această problemă făcând ca fiecare acțiune a agentului să fie verificabilă independent. Auditorul nu trebuie să aibă încredere în tine. Are nevoie doar de cheia ta publică și de chitanța î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 apelează un instrument] --> B[Construiește sarcina de date a chitanței]
B --> C[Canonicalizează JSON RFC 8785]
C --> E[Semnează biții canonici Ed25519]
E --> F[Chitanță cu semnătură]
F --> G[Auditorul verifică offline]
G --> H{Semnătura este validă?}
H -- yes --> I[Dovadă evidentă de manipulare]
H -- no --> J[Chitanță respinsă]
O chitanță minimală arată astfel:
{
"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 fac toată treaba:
Semnătura. Chitanța este semnată de gateway-ul agentului folosind o cheie privată Ed25519. Oricine are cheia publică corespunzătoare poate verifica semnătura offline. Orice modificare a unui câmp invalidează semnătura.
Codificare canonică. Înainte de semnare, chitanța este serializată folosind Schema de Canonicalizare JSON (JCS, RFC 8785). Acest lucru asigură că două implementări care produc aceeași chitanță logică produc ieșire identică la nivel de byte. Fără canonicalizare, diverși serializatori JSON ar produce semnături diferite pentru același conținut.
Lanț de hash-uri. Câmpul previous_receipt_hash leagă fiecare chitanță de cea anterioară. Eliminarea sau reordonarea unei chitanțe strică fiecare chitanță care a urmat după. Modificările devin vizibile la nivelul lanțului chiar dacă semnăturile individuale sunt ocolite.
Împreună, aceste proprietăți oferă trei garanții:
Nu ai nevoie de o bibliotecă specială pentru a produce o chitanță. Primitivele criptografice sunt disponibile pe scară largă iar logica este de câteva zeci de linii de Python.
Exercițiile practice din code_samples/18-signed-receipts.ipynb parcurg fluxul complet. Varianta rezumat:
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ă într-un seif de chei)
signing_key = signing.SigningKey.generate()
verify_key = signing_key.verify_key
# Construiește sarcina de date a chitanței (fără semnătură încă)
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,
}
# Canonicizează și semnează direct octeții JCS. PureEdDSA realizează intern hashing.
canonical_bytes = canonicalize(payload)
signature_bytes = signing_key.sign(canonical_bytes).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)),
},
}
Acesta este întregul flux de semnare. Exercițiile din notebook explică 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 payload-ul care a fost de fapt semnat (totul în afară de semnătură).
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
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țe de servicii, fără încredere în terți.
Pentru a vedea detectarea modificărilor în acțiune, notebook-ul parcurge:
tool_args_hash.Aceasta este demonstrația practică că chitanțele sunt evidente la modificări neautorizate: orice modificare, oricât de mică, strică semnătura.
O singură chitanță semnată protejează o acțiune. Un lanț de chitanțe protejează o secvență.
flowchart LR
R0[Chitanță 0<br/>genesis] --> 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 chitanța 2 fără urmă, un atacator ar trebui să:
previous_receipt_hash din chitanța 3 (strică semnătura chitanței 3), SAUDacă cheia privată este într-un seif hardware și publici cheia publică cu fiecare chitanță, niciunul dintre aceste atacuri nu este fezabil fără a fi detectat.
Notebook-ul parcurge:
previous_receipt_hash a fiecărei chitanțe corespunde hash-ului real al chitanței anterioare.Așa produci o urmă de audit pe care un auditor extern o poate verifica fără să aibă încredere în tine.
Aceasta este secțiunea cea mai importantă a acestei lecții. Chitanțele sunt puternice, dar puterea lor este limitată.
Chitanțele demonstrează trei lucruri:
Chitanțele NU demonstrează:
policy_id a fost efectiv evaluată sau că ar fi permis această acțiune dacă ar fi fost verificată. Chitanța înregistrează ceea ce s-a afirmat, nu ceea ce a fost impus.Această graniță este importantă din două motive:
O greșeală frecventă este să presupui că “avem chitanțe” înseamnă “suntem guvernați.” Nu este așa. Chitanțele sunt o bază. Guvernanța este sistemul pe care îl construiești peste această bază.
Punctul 3 de mai sus merită propria secțiune: o chitanță de acțiune spune “această cheie a semnat acest conținut,” niciodată “un om a autorizat asta.” Pentru acțiuni cu risc ridicat (returnări, ștergeri, transferuri bancare), cadrele de guvernanță cer din ce în ce mai mult această afirmație lipsă, iar ea poate fi produsă cu aceleași primitive pe care le-ai construit în această lecție.
Notebook-ul următor code_samples/human-authorization-receipts.ipynb adaugă un al doilea tip de chitanță, human.approval.v1, în aceeași formă de plic ca și chitanțele lecției (un payload tipizat semnat Ed25519 peste octeții săi JCS canonici, cu obiectul signature în afara octeților semnați). Un semnatar numit semnează acțiunea canonică completă și digestul acesteia înainte de execuție; chitanța de acțiune a agentului poartă același digest de acțiune și o referință parent_approval_ref, hash-ul chitanței aprobării, aceeași convenție ca previous_receipt_hash în lanțul construit anterior. O singură funcție verify_chain verifică ambele artefacte sub registre separate de chei fixate (cheile aprobatorului vs cheile agentului), deci drumul codului este comun, dar autoritățile nu sunt.
Proprietatea obținută, exprimată cu atenție: omul a aprobat această acțiune exactă, iar agentul a executat exact acea acțiune aprobată. Facilitățile de refuz din notebook sunt ceea ce face această proprietate reală și nu doar afirmată:
Fiecare eșec refuză cu un motiv distinct, astfel că un auditor care citește refuzul poate spune dacă autoritatea a expirat sau acțiunea executată s-a schimbat. Regula pe care o predă notebook-ul: o aprobare semnată nu este autoritate de una singură. Autoritatea există numai dacă ambele chitanțe încă leagă aceeași acțiune canonică la momentul execuției. Chitanța de aprobare umană este o compoziție educațională definită de această lecție, nu un tip de chitanță definit de draft-farley-acta-signed-receipts.
Codul Python din această lecție este intenționat minim pentru a putea citi fiecare linie și a înțelege exact ce se întâmplă. În producție, ai două opțiuni:
Construiește direct pe primitivele criptografice. Cele 50 de linii pe care le-ai 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.
Folosește o bibliotecă de chitanțe pentru producție. Mai multe proiecte open-source implementează același model cu funcționalități suplimentare (rotația cheilor, verificare în lot, distribuția setului JWK, integrare cu motoare de politici):
draft-farley-acta-signed-receipts, revizia 02). Chitanța educațională plată a lecției diferă de plicul {payload, signature} al draftului și nu este prezentată ca o implementare conformă. Draftul publică un set de conformitate comun (agent-governance-testvectors) pentru implementările care vizează formatul său de interschimb.protect-mcp (npm) și @veritasacta/verify (npm) oferă o implementare bazată pe Node pentru semnarea chitanțelor și verificarea offline, concepută pentru a înveli orice server MCP cu o urmă de audit evidentă pentru modificări, inclusiv un flux de co-semnare în care o acțiune pusă pe pauză emite o chitanță de aprobare legată de digestul acțiunii (susținută WebAuthn în fluxul desktop), același model de chitanță de aprobare ca în notebook-ul de autorizare umană de mai sus.pip install nobulex) oferă același model Ed25519 + JCS în Python cu integrări LangChain și CrewAI, inclusiv vectori de testare pentru validare încrucișată publicați și o mapare de conformitate contribuită prin OWASP PR #2210.Decizia dintre a scrie propriul cod și a folosi o bibliotecă reflectă decizia dintre 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 te obligă să înțelegi fiecare primitiv. Această lecție predă drumul de la zero pentru a avea fundația pentru oricare opțiune.
Testează-ți î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 verifica chitanța offline?
2. Un atacator modifică câmpul policy_id al unei chitanțe pentru a susține că a fost guvernată de o politică mai permisivă. Semnătura a fost făcută peste payload-ul original. Ce se întâmplă în timpul verificării?
3. De ce chitanța include un tool_args_hash și result_hash în loc de argumentele brute și rezultatul brut?
4. Câmpul previous_receipt_hash leagă fiecare chitanță de cea precedentă. Dacă un atacator șterge în liniște o chitanță din mijlocul lanțului, ce devine invalid?
5. O chitanță este verificată cu succes. Asta dovedește 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 trasabilitate), actualizează logica canonicală de semnare pentru a-l include și confirmă că chitanța încă trece verificarea. Apoi modifică câmpul după semnare și confirmă că verificarea eșuează. Acest lucru te forțează să înțelegi cum contribuie fiecare octet din codificarea canonică la semnătură.
Provocare suplimentară 2: Aplică SHA-256 pe două dintre chitanțele tale concatenate în ordine deterministă și încorporează digestul obținut ca un câmp nou pe o a treia chitanță înainte de semnare. Verifică că toate cele trei chitanțe trec 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:
Nu sunt un substitut pentru validarea intrărilor, aplicarea politicilor sau infrastructura de identitate. Sunt o fundație pentru aceste nivele. Când implementezi agenți în sarcini reglementate, în fluxuri multi-organizaționale sau orice context în care un auditor viitor nu poate fi presupus să aibă încredere în tine, chitanțele sunt modul prin care faci pista de audit onestă.
Cel mai important mesaj: chitanțele dovedesc cine a spus ce și când. Nu dovedesc că ceea ce a fost spus este adevărat sau corect. Păstrează această distincție strâns. 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 chitanțe semnate î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 învățăcei, a participa la ore de consultanță și a primi răspunsuri la întrebările tale despre agenții AI.
Această lecție acoperă semnarea unei singure chitanțe și secvențe înlănțuite prin hash. Aceleași primitive formează mai multe modele avansate pe care le poți întâlni pe măsură ce postura ta de guvernanță se maturizează:
authorization_*) și post-execuție (result_*) cu semnături independente, utile când decizia de autorizare și rezultatul observat sunt produse de actori diferiți sau la momente diferite. Acest model se adaugă peste formatul chitanței predat în această lecție.result_hash. Încărcăturile din lumea reală sunt adesea mai bogate decât un simplu rezultat apel tool: raționamentul pre-decidere (predicția modelului, opțiunile considerate, dovezile și cât de complete sunt, postura de risc, lanțul de responsabilitate, rezultatul porții) pot trăi toate în încărcătură, sigilate de o singură chitanță. Aceasta păstrează formatul chitanței minimal, permițând totodată evoluția schemelor specifice domeniului.signature.alg poate purta ML-DSA-65 (standardul NIST de semnătură post-cuantică) când ai nevoie să migrezi. Planifică o perioadă de tranziție în care chitanțele sunt 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.