Погледајте видео час: Осигуравање AI агената криптографским потписима
(Видео час и сличица ће додати Microsoft тим за садржај након спајања, у складу са шаблоном лекције 14 / 15.)
Ова лекција ће обухватити:
Након завршетка ове лекције знаћете како да:
Замислите да сте распоредили AI агента за Contoso Travel. Агент чита захтеве корисника, позива API за летове да прегледа опције и резервише седишта у име корисника. Прошлог квартала, агент је обрадио 50.000 резервација.
Данас стиже ревизор. Поставља једноставно питање: “Покажите ми шта је ваш агент радио.”
Предате му датотеке са логовима. Ревизор их погледа и поставља тежје питање: “Како да знам да ти логови нису измењени?”
Ово је проблем аудиторског трага. Већина садашњих распореда агената се ослања на:
Ниједан од ових начина не може одговорити на питање ревизора без дага је он или она приморани да верују некоме (вама, вашем добављачу облака, добављачу базе података). За унутрашњу употребу, то је често прихватљиво. За регулисане радне задатке (финансије, здравство, све што подлеже EU AI Act-у), није.
Криптографски потписи решавају овај проблем тиме што свака радња агента може бити независно верификована. Ревизор вам не мора веровати. Потребан му је само ваш јавни кључ и сам потпис.
Потпис је JSON објекат који бележи шта је агент урадио, потписан дигиталним потписом.
flowchart LR
A[Агент покреће алатку] --> B[Изградити податке рачуна]
B --> C[Канонизуј JSON RFC 8785]
C --> D[SHA-256 хеш]
D --> E[Ed25519 потпис]
E --> F[Рачун са потписом]
F --> G[Ревизор верификује офлајн]
G --> H{Потпис важећи?}
H -- да --> I[Доказ отпоран на измјене]
H -- не --> J[Рачун одбијен]
Минимални потпис изгледа овако:
{
"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..."
}
}
Три особине раде сав посао:
Потпис. Потпис је израдио gateway агента користећи Ed25519 приватни кључ. Свако са одговарајућим јавним кључем може ван мреже проверити потпис. Манипулација било којим пољем онемогућава потпис.
Канонско кодирање. Пре потписивања, потпис се сереалзује коришћењем JSON Canonicalization Scheme (JCS, RFC 8785). Ово осигурава да две имплементације које произведу исти логички потпис дају идентичан бајт-излаз. Без канонизације, различити JSON серијализатори давали би различите потписе за исти садржај.
Хеш-ланч. Поље previous_receipt_hash повезује сваки потпис са претходним. Уклањање или прераспоређивање потписа нарушава сваки следећи потпис. Манипулације постају видљиве на нивоу ланца чак и ако појединачни потписи буду заобиђени.
Заједно ове особине дају три гарантовања:
Не треба вам посебна библиотека да произведете потпис. Криптографски примитиви су широко доступни а логика је неколико десетина редова Python кода.
Практични задаци у code_samples/18-signed-receipts.ipynb воде кроз цео процес. Сажети приказ:
import json
import hashlib
import base64
from nacl import signing
from jcs import canonicalize # 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()}"
# Генериши или учитај кључ за потписивање (у производњи, чувај у складишту кључева)
signing_key = signing.SigningKey.generate()
verify_key = signing_key.verify_key
# Изгради податке рачуна (још без потписа)
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,
}
# Канонизуј, хеширај, потпиши.
canonical_bytes = canonicalize(payload)
message_hash = hashlib.sha256(canonical_bytes).digest()
signature_bytes = signing_key.sign(message_hash).signature
# Прикључи структуирани објекат потписа.
receipt = {
**payload,
"signature": {
"alg": "EdDSA",
"sig": b64url_nopad(signature_bytes),
"public_key": b64url_nopad(bytes(verify_key)),
},
}
То је цео потписивачки процес. Вежбе у notebook-у покривају сваки корак.
Верификација је обрнути процес:
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:
# Потпис је структуриран објекат: {"alg", "sig", "public_key"}.
sig_obj = receipt.get("signature")
if not sig_obj or sig_obj.get("alg") != "EdDSA":
return False
# Реконструишите корисни садржај који је заправо потписан (све осим потписа).
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
Ова функција узима потпис и враћа True ако је потпис важећи, False у супротном. Без мрежних позива, без зависности од сервиса, без потребе да се верује трећој страни.
Да бисте видели како се откривају манипулације, notebook води кроз:
tool_args_hash.Ово је практични доказ да су потписи видљиви на манипулације: било каква измена, ма колико мала, нарушава потпис.
Један потпис штити једну акцију. Ланац потписа штити низ акција.
flowchart LR
R0[Рачун 0<br/>генеза] --> R1[Рачун 1]
R1 --> R2[Рачун 2]
R2 --> R3[Рачун 3]
R1 -. previous_receipt_hash .-> R0
R2 -. previous_receipt_hash .-> R1
R3 -. previous_receipt_hash .-> R2
Сваки потпис бележи хеш претходног потписа. Да би нападач тихо уклонио потпис 2, морао би да:
previous_receipt_hash потписа 3 (чиме се нарушава потпис потписа 3), ИЛИАко је приватни кључ у хардверском кључном складишту а јавни кључ објављује се уз сваки потпис, ниједан од ова два напада није могућ без детекције.
Notebook пролази кроз:
previous_receipt_hash сваког потписа слаже са стварним хешом претходног потписа.Ово је начин на који произведите аудиторски траг који спољни ревизор може верификовати без потребе да вама верује.
Ово је најважнији део лекције. Потписи су моћни али њихова моћ има границе.
Потписи доказују три ствари:
Потписи НЕ доказују:
policy_id заиста процењена, или да би дозволила ову радњу ако би била проверена. Потпис бележи шта је тврдило, а не шта је спроведено.Ова граница је важна из два разлога:
Честа грешка је претпоставка да „имамо потписе“ значи „имамо управу“. Не значи. Потписи су основа. Управа је систем који градиш преко те основе.
Python код у овој лекцији је намерно минималан да бисте сваки ред прочитали и разумели шта се тачно дешава. У продукцији имате две опције:
Радити директно са криптографским примитивима. 50 редова које сте видели горе је довољно за многе примене. PyNaCl (Ed25519) и пакeт jcs (канонски JSON) су добро одржаване и ревидиране библиотеке.
Користити библиотеку за потписе у продукцији. Неколико пројеката отвореног кода имплементира исти образац са додатним функцијама (ротација кључева, пакетна верификација, дистрибуција JWK скупа, интеграција са мотором политика):
draft-farley-acta-signed-receipts) који је тренутно у процесу стандардизације.protect-mcp (npm) и @veritasacta/verify (npm) пружају Node-имплементацију потписивања потписа и верификације ван мреже, намењену за заштиту било ког MCP сервера аудиторским путем отпорним на манипулације.Одлука између прављења сопственог решења и коришћења библиотеке је као одлука између писања сопствене JWT библиотеке и коришћења тестиранe: обе су разумне; библиотека штеди време и смањује површину за ревизију; приступ од нуле вас тера да разумете сваки примитив. Ова лекција вас учи приступу од нуле тако да имате темељ за било који избор.
Тестирајте своје разумевање пре него што кренете на практични задатак.
1. Потпис је направљен Ed25519 приватним кључем агента. Ревизор има само јавни кључ. Може ли ревизор ван мреже проверити потпис?
2. Нападач мења поље policy_id у потпису да тврдњом каже да је политика била попустљивија. Потпис је направљен преко оригиналног садржаја. Шта се дешава при верификацији?
3. Зашто потпис садржи tool_args_hash и result_hash уместо сирових аргумената и резултата?
4. Поље previous_receipt_hash повезује сваки потпис са претходним. Ако нападач тихо избрише један потпис из средине ланца, шта постаје неважеће?
5. Потпис се успешно верификује. Да ли то доказује да је радња агента била исправна, ваљана или усклађена са политиком?
Отворите code_samples/18-signed-receipts.ipynb и завршите свe четири секције:
Изазов 1: проширите шему потписа додатним пољем по вашем избору (нпр. ID захтева за праћење), ажурирајте канонски логички потпис да га укључује и потврдите да потпис и даље пролази верификацију. Затим измените то поље после потписивања и потврдите да верификација пада. Ово вас тера да разумете како сваки бајт канонског кодирања доприноси потпису. Изазов за напредне (Stretch) 2: Хеширајте два своја рачуна помоћу SHA-256 заједно (конкатенишите њихове канонске бајтове у детерминисаном редоследу) и уградите добијени дигест као ново поље на трећи рачун пре него што га потпишете. Проверите да ли се сва три рачуна и даље могу верификовати у читавом кругу. Управо сте направили једностепени доказ укључености: сваки носилац трећег рачуна може доказати да су прва два постојала у време када је рачун потписан, без потребе да открива њихов садржај. Ово је образац који рачуни са селективним откривањем користе на широком нивоу (Меркле обавезе, RFC 6962).
Криптографски рачуни дају AI агентима траг ревизије који је:
Они нису замена за валидацију уноса, примену политика или инфраструктуру идентитета. Они су темељ за те нивое. Када уграђујете агенте у регулаторна оптерећења, мултиорганизационе токове рада или било које окружење у којем се не може претпоставити да ће будући ревизор веровати вама, рачуни су начина да траг ревизије учините поузданим.
Најважнија порука: рачуни доказују ко је шта рекао и када. Они не доказују да је оно што је речено тачно или исправно. Чврсто држите ту разлику. То је разлика између поузданог система порекла и обмањујућег.
Када будете спремни да напустите ову лекцију и примените агенте са потписаним рачунима у стварном окружењу:
https://your-org.example.com/.well-known/agent-keys.json.Придружите се Microsoft Foundry Discord за дружење са другим учесницима, посету канцеларијских сати и добијање одговора на питања о AI агентима.
Ова лекција покрива потписивање појединачног рачуна и низове повезане хешевима. Исти примитиви се комбинују у неколико напреднијих образаца на које можете наићи како ваш систем управљања буде напредовао:
authorization_*) и после извршења (result_*) са независним потписима, корисно када одлуку о ауторизацији и посматрани резултат производе различити актери или у различито време. Ово се додатно комбинује са форматом рачуна објашњеним у овој лекцији.result_hash. Прави садржаји су често богатији од резултата једног алата: предодлучивачко расуђивање (предвиђање модела, размотрене опције, докази и њихова потпуност, ризично стање, ланац одговорности, исход провере) могу све бити унутар садржаја, запечаћени једним рачуном. Ово одржава формат рачуна минималним, док дефиниције садржаја могу еволуирати по доменима.signature.alg може носити ML-DSA-65 (Нист-ов стандард за постквантне потписе) када је потребно мигрирати. Планирајте период транзиције у коме су рачуни потписани дупло.Изградња агената за коришћење рачунара (CUA)
(Одлучују уредници курикулума)
Изјава о одрицању одговорности: Овај документ је преведен коришћењем услуге за аутоматски превод Co-op Translator. Иако тежимо тачности, имајте у виду да аутоматски преводи могу садржати грешке или нетачности. Оригинални документ на његовом изворном језику треба сматрати ауторитативним извором. За критичне информације препоручује се професионални људски превод. Нисмо одговорни за било каква неспоразума или погрешна тумачења која произилазе из коришћења овог превода.