Гледайте видеоурока: Осигуряване на AI Агенти с Криптографски Квитанции
(Видео урок и миниатюра ще бъдат добавени от екипа за съдържание на Microsoft след обединяването, съвпадащи с модела за урок 14 / 15.)
Този урок ще обхване:
След завършване на този урок ще знаете как да:
Представете си, че сте разположили AI агент за Contoso Travel. Агентът чете заявки от клиенти, извиква API за полети за проверка на опции и резервира места от името на клиента. Миналото тримесечие агентът обработи 50 000 резервации.
Днес пристига одитор. Той задава прост въпрос: “Покажете ми какво е направил вашият агент.”
Предавате файловете с логове. Одиторът ги разглежда и задава по-трудния въпрос: “Как да знам, че тези логове не са били редактирани?”
Това е проблемът с аудит траила. Повечето внедрения на агенти днес разчитат на:
Нито един от тези не може да отговори на въпроса на одитора без одиторът да се довери на някого (вас, доставчика на облак, доставчика на базата данни). За вътрешна употреба това доверие често е приемливо. За регулирани работни натоварвания (финанси, здравеопазване, всичко подлежащо на EU AI Act) – не е.
Криптографските квитанции решават това, като правят всяко действие на агента независимо проверимо. Одиторът не трябва да ви се доверява. Той се нуждае само от публичния ви ключ и самата квитанция.
Квитанцията е JSON обект, който записва какво е направил агентът, подписан с дигитален подпис.
flowchart LR
A[Агент извиква инструмент] --> B[Създаване на полезен товар на бележка]
B --> C[Канонизиране на JSON RFC 8785]
C --> E[Подписване на канонични байтове с Ed25519]
E --> F[Бележка с подпис]
F --> G[Одитор проверява офлайн]
G --> H{Подписът валиден ли е?}
H -- yes --> I[Доказателство за манипулация]
H -- no --> 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..."
}
}
Три свойства извършват работата:
Подписът. Квитанцията е подписана от шлюза на агента с 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 # Каноничен JSON според 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,
}
# Канонизиране и подписване на JCS байтовете директно. PureEdDSA извършва хеширане вътрешно.
canonical_bytes = canonicalize(payload)
signature_bytes = signing_key.sign(canonical_bytes).signature
# Прикачване на структурирана обект за подпис.
receipt = {
**payload,
"signature": {
"alg": "EdDSA",
"sig": b64url_nopad(signature_bytes),
"public_key": b64url_nopad(bytes(verify_key)),
},
}
Това е цялата верига на подписване. Упражненията в тетрадката разглеждат всяка стъпка.
Проверката е обратната операция:
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)
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
Тази функция приема квитанция и връща True, ако подписът е валиден, и False в противен случай. Без мрежови повиквания, без зависимости от услуги, без необходимост от доверие към трета страна.
За да видите засичане на подправяне в действие, тетрадката разглежда:
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), ИЛИАко частният ключ се пази в хардуерен ключов хранилище и публикувате публичния ключ с всяка квитанция, нито една атака не е възможна без да бъде засечена.
Тетрадката разглежда:
previous_receipt_hash на всяка квитанция съвпада с действителния хеш на предишната квитанция.Това е как се създава аудит траил, който външен одитор може да потвърди без да ви се доверява.
Това е най-важната част от този урок. Квитанциите са мощни, но силата им е ограничена.
Квитанциите доказват три неща:
Квитанциите НЕ доказват:
policy_id, наистина е била оценена или че би позволила това действие при проверка. Квитанцията отчита какво е твърдено, не какво е било наложено.Тази граница е важна по две причини:
Често срещана грешка е да се мисли, че “имаме квитанции” означава “управляваме се.” Не е така. Квитанциите са основа. Управлението е системата, която изграждате върху нея.
Точка 3 по-горе заслужава собствена секция: квитанцията за действие казва “този ключ е подписал това съдържание,” никога “човек е упълномощил това.” За рискови действия (връщания, изтривания, банкови преводи), рамките за управление все повече изискват точно това липсващо изявление и то може да бъде произведено със същите примитиви, които вече сте изградили в този урок.
Продължаващата тетрадка code_samples/human-authorization-receipts.ipynb добавя втори вид квитанция, human.approval.v1, със същата форма като тази на урока (типизиран полезен товар, подписан с Ed25519 върху каноничните JCS байтове, с обект signature отвън на подписаните байтове). Назован упълномощител подписва пълното канонично действие и неговия дайджест преди изпълнение; квитанцията за действие на агента носи същия дайджест на действие и parent_approval_ref, receipt_hash на одобрението, същият конвенционален подход като previous_receipt_hash във веригата, която изгради по-горе. Един verify_chain проверява двата артифакта под отделни регистрирани ключове (ключовете на упълномощителите срещу ключовете на агента), така че пътят на кода е споделен, но властите никога.
Свойството, което това дава, формулирано внимателно: човекът е одобрил точно това действие, и агентът е изпълнил точно това одобрено действие. Отказите в тетрадката правят това свойство реално, а не просто твърдение:
Всеки отказ има различна причина, така че одитор, който чете отказ, може да разбере дали властта е изтекла или изпълненото действие е променено. Правилото, което тетрадката учи: подписаното одобрение само по себе си не е власт. Власт има само ако и двете квитанции все още се отнасят към едно и също канонично действие към момента на изпълнението. Квитанцията за човешко одобрение е образователна композиция, дефинирана от този урок, не е тип квитанция, дефиниран в draft-farley-acta-signed-receipts.
Python кодът в този урок е умишлено минимален, така че да можете да прочетете всеки ред и да разберете точно какво се случва. В продукция имате две опции:
Изградете директно върху криптографските примитиви. 50-те реда, които видяхте по-горе, са достатъчни за много случаи на употреба. PyNaCl (Ed25519) и пакетът jcs (каноничен JSON) са добре поддържани и одитирани библиотеки.
Използвайте продукционна библиотека за квитанции. Няколко проекта с отворен код реализират същия модел с допълнителни функции (ротация на ключове, групова верификация, разпространение на JWK Set, интеграция с политически механизми):
draft-farley-acta-signed-receipts, ревизия 02). Образователната плоска квитанция в този урок се различава от плика {payload, signature} в проекта и не се представя като съвместима имплементация. Проектът публикува обща тестова сесия (agent-governance-testvectors) за имплементации, насочени към неговия формат на проводник.protect-mcp (npm) и @veritasacta/verify (npm) предоставят Node-базирана имплементация за подписване и офлайн верификация на квитанции, предназначени за обвиване на всеки MCP сървър с аудиторска следа видима за подправяне, включително поток с изчакване и съ-сигурност, където паузирано действие издава квитанция за одобрение, обвързана с дайджеста на действието (поддържано чрез WebAuthn на настолно приложение), същият модел за одобрение-квитанция като в гореспоменатата тетрадка за човешка авторизация.pip install nobulex) предоставя същия Ed25519 + JCS подписващ модел в Python с интеграции на LangChain и CrewAI, включително публикувани тестови вектори за крос-валидация и карта за съответствие, предоставена чрез OWASP PR #2210.Решението между самостоятелна разработка и използване на библиотека е като решението между писане на собствен JWT библиотека и използване на тествана: и двете са разумни; библиотеката пести време и намалява обема за одит; подходът от нулата ви принуждава да разберете всеки примитив. Този урок преподава подхода от нулата, за да имате основата за всеки избор.
Изпитайте своето разбиране преди да преминете към практическото упражнение.
1. Квитанцията е подписана с частния Ed25519 ключ на агента. Одиторът има само публичния ключ. Може ли одиторът да провери квитанцията офлайн?
2. Нападател променя полето policy_id в квитанцията, твърдейки че е управлявана от по-разрешителна политика. Подписът е върху оригиналния полезен товар. Какво се случва при верификация?
3. Защо разписката включва tool_args_hash и result_hash, вместо суровите аргументи и резултата?
4. Полето previous_receipt_hash свързва всяка разписка с предшественика ѝ. Ако нападател тихомълком изтрие една разписка от средата на верига, какво става невалидно?
5. Разписката се проверява успешно. Това доказва ли, че действието на агента е било правилно, разумно или съобразено с политиката?
Отворете code_samples/18-signed-receipts.ipynb и завършете всичките четири секции:
Разширено предизвикателство 1: разширете схемата на разписката с допълнително поле по ваш избор (например идентификатор на заявка за проследяване), актуализирайте логиката за канонично подписване да го включва и потвърдете, че разписката все още преминава проверката. След това променете полето след подписване и се уверете, че проверката не успява. Това ви кара да разберете как всеки байт от каноничното кодиране допринася за подписа.
Разширено предизвикателство 2: SHA-256 хеширайте две от вашите разписки заедно (конкатенирайте техните канонични байтове в детерминиран ред) и вградете получения дайджест като ново поле в трета разписка преди да я подпишете. Проверете, че и трите разписки все още преминават проверката. Току-що сте изградили едностъпково доказателство за включване: всеки държащ третата разписка може да докаже, че първите две са съществували към момента на подписване, без да разкрива съдържанието им. Това е моделът, който използват разписки със селективно разкриване в мащаб (Merkle ангажименти, 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 (пост-квантовият стандарт за цифров подпис на NIST), когато се наложи миграция. Планирайте преходен период с двойно подписване на разписките.Създаване на локални AI агенти
Отказ от отговорност: Този документ е преведен с помощта на AI преводачески услуга Co-op Translator. Въпреки че се стремим към точност, моля имайте предвид, че автоматизираните преводи могат да съдържат грешки или неточности. Оригиналният документ на неговия роден език трябва да се счита за авторитетен източник. За критична информация се препоръчва професионален човешки превод. Ние не носим отговорност за каквито и да е недоразумения или неправилни тълкувания, произтичащи от използването на този превод.