Katso oppituntivideo: Tekoälyagenttien suojaaminen kryptografisilla kuiteilla
(Oppituntivideo ja pikkukuva lisätään Microsoftin sisältötiimin toimesta yhdistämisen jälkeen, vastaamaan oppituntien 14 / 15 kaavaa.)
Tässä oppitunnissa käsitellään:
Tämän oppitunnin suorittamisen jälkeen osaat:
Kuvittele, että olet ottanut käyttöön tekoälyagentin Contoso Travelille. Agentti lukee asiakaspyyntöjä, kutsuu lentotietopalvelun APIa etsiäkseen vaihtoehtoja ja varaa paikkoja asiakkaan puolesta. Viime neljänneksellä agentti käsitteli 50 000 varausta.
Tänään tarkastaja saapuu. Hän esittää yksinkertaisen kysymyksen: “Näytä, mitä agenttisi teki.”
Luovutat lokitiedostot. Tarkastaja katsoo niitä ja esittää vaikeamman kysymyksen: “Mistä tiedän, etteivät nämä lokit ole muokattuja?”
Tämä on tarkastusloki-ongelma. Useimmat agenttien käyttöönotot nykyään luottavat:
Mikään näistä ei voi vastata tarkastajan kysymykseen ilman, että tarkastaja luottaa johonkuhun (sinä, pilvipalveluntarjoajasi, tietokantamyyjäsi). Sisäisessä käytössä tämä luottamus on usein hyväksyttävää. Säännellyissä työkuormissa (rahoitus, terveydenhuolto, mikä tahansa EU:n tekoälyasetuksen alainen) se ei ole.
Kryptografiset kuitit ratkaisevat tämän tekemällä jokaisesta agentin toimenpiteestä itsenäisesti varmennettavan. Tarkastajan ei tarvitse luottaa sinuun. Tarvitaan vain julkinen avain ja kuitti.
Kuitti on JSON-objekti, joka tallentaa, mitä agentti teki, allekirjoitettuna digitaalisesti.
flowchart LR
A[Agentti kutsuu työkalua] --> B[Luo kuittipaketti]
B --> C[Normalisoi JSON RFC 8785:n mukaisesti]
C --> E[Allekirjoita Ed25519-kanooniset tavut]
E --> F[Kuitti allekirjoituksella]
F --> G[Tarkastaja vahvistaa offline-tilassa]
G --> H{Onko allekirjoitus voimassa?}
H -- yes --> I[Väärennöksiltä suojattu todiste]
H -- no --> J[Kuitti hylätty]
Minimikuitti näyttää tältä:
{
"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..."
}
}
Kolme ominaisuutta tekee työn:
Allekirjoitus. Kuitti on allekirjoitettu agentin portin toimesta Ed25519-yksityisavaimella. Jokainen vastaavan julkisen avaimen omaava voi varmistaa allekirjoituksen offline-tilassa. Kentän manipulointi kumoaa allekirjoituksen.
Kanoninen koodaus. Ennen allekirjoitusta kuitti serialisoidaan JSON Canonicalization Scheme (JCS, RFC 8785) -standardin mukaisesti. Tämä varmistaa, että kaksi toteutusta, jotka tuottavat loogisesti saman kuitin, tuottavat myös identtisen tavujonon. Ilman kanonisointia eri JSON-serialisointiohjelmat tuottaisivat erilaisia allekirjoituksia samalle sisällölle.
Hash-ketjutus. previous_receipt_hash -kenttä linkittää jokaisen kuitin sitä edeltävään. Yhden kuitin poistaminen tai uudelleenjärjestäminen katkaisee kaikki sitä seuraavat kuitit. Manipulointi näkyy ketjutason tarkastuksessa, vaikka yksittäiset allekirjoitukset ohitettaisiin.
Nämä ominaisuudet yhdessä tarjoavat kolme takuuta:
Kuittia ei tarvitse tuottaa erikoiskirjastolla. Kryptografiset perustoiminnot ovat laajalti saatavilla, ja logiikka on muutama kymmenen riviä Pythonia.
Käytännön harjoitukset tiedostossa code_samples/18-signed-receipts.ipynb käyvät läpi koko prosessin. Tiivistelmä:
import json
import hashlib
import base64
from nacl import signing
from jcs import canonicalize # RFC 8785 kanoninen 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()}"
# Luo tai lataa allekirjoitusavain (tuotannossa tallenna avainholviin)
signing_key = signing.SigningKey.generate()
verify_key = signing_key.verify_key
# Rakenna kuittausaineisto (ei vielä allekirjoitusta)
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,
}
# Kanonisoi ja allekirjoita JCS-tavuerä suoraan. PureEdDSA hajauttaa sisäisesti.
canonical_bytes = canonicalize(payload)
signature_bytes = signing_key.sign(canonical_bytes).signature
# Liitä rakenteellinen allekirjoitusobjekti.
receipt = {
**payload,
"signature": {
"alg": "EdDSA",
"sig": b64url_nopad(signature_bytes),
"public_key": b64url_nopad(bytes(verify_key)),
},
}
Tämä on koko allekirjoitusketju. Harjoituksissa käydään läpi jokainen vaihe.
Varmennus on käänteistoiminto:
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:
# Allekirjoitus on jäsennelty objekti: {"alg", "sig", "public_key"}.
sig_obj = receipt.get("signature")
if not sig_obj or sig_obj.get("alg") != "EdDSA":
return False
# Rakenna uudelleen ladattu tieto, joka allekirjoitettiin (kaikki paitsi allekirjoitus).
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
Tämä funktio ottaa kuitin ja palauttaa True jos allekirjoitus on voimassa, muuten False. Ei verkkokutsua, ei palveluriippuvuutta, ei luottamusta kolmansiin osapuoliin.
Havaitsemanäytteen mukaan harjoituksissa käydään läpi:
tool_args_hash -kentässä.Tämä osoittaa käytännössä, että kuitit ovat manipulointia osoittavia: mikä tahansa muutos, kuinka pieni tahansa, rikkoo allekirjoituksen.
Yksi allekirjoitettu kuitti suojaa yhtä toimintoa. Kuittiketju suojaa toimintojonon.
flowchart LR
R0[Kuitti 0<br/>alku] --> R1[Kuitti 1]
R1 --> R2[Kuitti 2]
R2 --> R3[Kuitti 3]
R1 -. previous_receipt_hash .-> R0
R2 -. previous_receipt_hash .-> R1
R3 -. previous_receipt_hash .-> R2
Jokainen kuitti tallentaa sitä edeltävän kuitin hashin. Jos hyökkääjä haluaisi poistaa kuitin 2 huomaamatta, hänen pitäisi joko:
previous_receipt_hash -kenttää (rikkoo kuitin 3 allekirjoituksen), TAIJos yksityisavain on turvallisessa laiterahastossa ja julkinen avain julkaistaan jokaisen kuitin mukana, kumpikaan hyökkäys ei ole mahdollinen ilman havaitsemista.
Harjoitustiedosto käy läpi:
previous_receipt_hash vastaa edellisen kuitin todellista hashia.Näin tuotat tarkastusloki, jonka ulkoinen tarkastaja voi varmentaa ilman, että hänen tarvitsee luottaa sinuun.
Tämä on oppitunnin tärkein osio. Kuitit ovat tehokkaita mutta niiden voima on rajattu.
Kuitit todistavat kolme asiaa:
Kuitit eivät todista:
policy_id-kentässä viitattu säännöstö olisi arvioitu tai että se olisi sallinut toiminnon. Kuitti tallentaa, mitä väitettiin, ei mitä toteutettiin.Tämä raja on tärkeä kahdesta syystä:
Tavallinen virhe on olettaa, että “meillä on kuitit” tarkoittaa “meitä valvotaan”. Ei tarkoita. Kuitit ovat perusta. Valvontajärjestelmä on sen päälle rakennettava kokonaisuus.
Kohta 3 on oman osionsa arvoinen: toimintakuitti sanoo “tämä avain allekirjoitti tämän sisällön”, ei koskaan “tämä ihminen valtuutti tämän”. Korkean riskin toimille (hyvitykset, poistot, tilisiirrot) hallintakehykset vaativat yhä useammin juuri tämän puuttuvan lausunnon, ja se on tuotettavissa samoilla perustoiminnoilla, jotka opit tässä oppitunnissa.
Jatkotyöstävä muistio code_samples/human-authorization-receipts.ipynb lisää toisen kuittilajin, human.approval.v1, oppitunnin kuittien kanssa samaan kuoreen (tyypitetty payload allekirjoitettuna Ed25519:llä kanonisista JCS-tavuista, signature-objekti allekirjoitettujen tavujen ulkopuolella). Nimetty hyväksyjä allekirjoittaa koko kanonisen toiminnon ja sen tiivisteen ennen suorittamista; agentin toimintakuitti kantaa saman toimen tiivisteen ja parent_approval_ref -kentän, hyväksynnän receipt_hash:n, samalla kaavalla kuin previous_receipt_hash ketjussa yllä. Yksi verify_chain vahvistaa molemmat artefaktit eri kiinnitettyjen avainrekistereiden avulla (hyväksyjän avaimet vs agentin avaimet), joten koodipolku on yhteinen mutta toimivaltuudet eivät koskaan.
Täsmällisesti ilmaistuna tämä takaa: ihminen hyväksyi juuri tämän toiminnon, ja agentti suoritti täsmälleen sen hyväksytyn toiminnon. Muistion kieltäytymiesimerkit tekevät ominaisuudesta todellisen eikä vain väitteen:
Kukin virhe hylätään eri syystä, joten tarkastaja voi silmäillä hylkäyksen syyn erottelevasti: toimivalta meni vanhaksi vai toiminto muuttui. Oppikirjan sääntö: allekirjoitettu hyväksyntä ei yksin ole toimivalta. Toimivalta on olemassa vain, jos molemmat kuitit sitovat samaa kanonista toimintoa suoritusaikana. Ihmisen hyväksyntäkuitti on tämän oppitunnin opetuskoostumus, ei kuittityyppi draft-farley-acta-signed-receipts -määrittelystä.
Python-koodi tässä oppitunnissa on tarkoituksella minimaalista, jotta voit lukea jokaisen rivin ja ymmärtää tarkalleen, mitä tapahtuu. Tuotantoa varten sinulla on kaksi vaihtoehtoa:
Rakenna suoraan kryptografisille perustoiminnoille. Yli 50 riviä yllä riittää moneen käyttötapaukseen. PyNaCl (Ed25519) ja jcs-paketti (kanoninen JSON) ovat hyvin ylläpidettyjä ja auditoituja kirjastoja.
Käytä tuotantokuittikirjastoa. Useat avoimen lähdekoodin projektit toteuttavat saman kaavan lisäominaisuuksilla (avainten kierto, erävarmennus, JWK nippujen jakelu, integrointi sääntömootoreihin):
draft-farley-acta-signed-receipts, versio 02). Tämän oppitunnin yksinkertaisempi opetuskuitti eroaa luonnoksen {payload, signature} -kuoresta eikä ole esitetty virallisena toteutuksena. Luonnos julkaisee yhteisen vaatimustenmukaisuussarjan (agent-governance-testvectors) toteutuksille, jotka kohdistuvat sen lankamuotoon.protect-mcp (npm) ja @veritasacta/verify (npm) paketit tarjoavat Node-pohjaisen toteutuksen kuitujen allekirjoittamiseen ja offline-varaamiseen, tarkoitettuna minkä tahansa MCP-palvelimen suojaamiseen manipulointia osoittavalla tarkastuslokilla, mukaan lukien hallittu yhteisallekirjoitusvirta, jossa pysäytetty toiminto tuottaa hyväksyntäkuittin sidottuna toiminnon tiivisteeseen (WebAuthn-tuettu työpöytävirrassa), sama hyväksyntäkuittimalli kuin edellä ihmisen valtuutuksen muistiossa.pip install nobulex) tarjoaa saman Ed25519 + JCS allekirjoituskaavan Pythonissa LangChain- ja CrewAI-integraatioilla, mukaan lukien julkaistut ristivarmennustestivektorit ja vaatimustenmukaisuuskartta, joka on kontribuoitu OWASP PR #2210.Päätös tehdä itse tai käyttää kirjastoa muistuttaa valinnasta kirjoittaa oma JWT-kirjasto tai käyttää testattua: molemmat ovat järkeviä; kirjasto säästää aikaa ja vähentää auditointipinta-alaa; omatekoisena oppii jokaisen perustoiminnon. Tämä oppitunti opettaa omatekoisen polun, jotta sinulla on perusta molempiin vaihtoehtoihin.
Testaa ymmärrystäsi ennen käytännön harjoitusta.
1. Kuitti on allekirjoitettu agentin yksityisellä Ed25519-avaimella. Tarkastajalla on vain julkinen avain. Voiko tarkastaja varmistaa kuitin offline-tilassa?
2. Hyökkääjä muuttaa kuitin policy_id -kenttää väittääkseen, että sitä hallitsi sallivampi sääntö. Allekirjoitus kuitenkin kattoi alkuperäisen payloadin. Mitä tapahtuu varmennuksessa?
3. Miksi kuitti sisältää tool_args_hash- ja result_hash-kentät raakojen argumenttien ja tuloksen sijasta?
4. previous_receipt_hash-kenttä linkittää jokaisen kuitin edeltäjäänsä. Jos hyökkääjä salaa poistaa yhden kuitin ketjun keskeltä, mikä muuttuu virheelliseksi?
5. Kuitti tarkastetaan onnistuneesti. Todistaako se, että agentin toiminta oli oikea, järkevä tai sääntöjen mukainen?
Avaa code_samples/18-signed-receipts.ipynb ja suorita kaikki neljä osaa:
Lisähaaste 1: laajenna kuittitietomallia omalla lisäkentälläsi (esim. pyyntö-ID jäljitykseen), päivitä kanoninen allekirjoituslogiikka sisällyttämään se ja varmista että kuitti käy läpi varmennuksen. Muokkaa sitten kenttää allekirjoituksen jälkeen ja varmista varmennuksen epäonnistuminen. Tämä pakottaa ymmärtämään, miten jokainen tavujono kanonisessa koodauksessa vaikuttaa allekirjoitukseen.
Lisähaaste 2: Tee SHA-256-tiiviste kahdesta kuitistasi (liitä niiden kanoniset tavut määrätietoisesti) ja upota tuloksena oleva tiiviste kolmannen kuitin uuteen kenttään ennen sen allekirjoittamista. Varmista, että kaikki kolme kuittia käyvät läpi varmennuksen. Olet juuri rakentanut yhden askeleen sisältötodistuksen: kuka tahansa, joka omistaa kolmannen kuitin, voi todistaa, että kaksi ensimmäistä oli olemassa allekirjoitushetkellä paljastamatta niiden sisältöä. Tätä mallia käyttää suurissa mittakaavoissa valikoiva paljastus (Merkle-sitoumukset, RFC 6962).
Kryptografiset kuitit antavat tekoälyagenteille auditointiketjun, joka on:
Ne eivät korvaa syötevalidointia, sääntöjen noudattamista tai identiteettirakenteita. Ne ovat näiden tasojen perusta. Kun otat agentteja käyttöön säädellyissä työkuormissa, moni-organisaatiotyönkuluissa tai missä tahansa tilanteessa, jossa tuleva tarkastaja ei voi luottaa suoraan sinuun, kuitit ovat keino tehdä auditointiketjusta rehellinen.
Tärkein opetus: kuitit todistavat kuka sanoi mitä ja milloin. Ne eivät todista, että sanottu oli totta tai oikein. Pidä tämä ero tarkasti mielessä. Se on rehellisen alkuperäisjärjestelmän ja harhaanjohtavan ero.
Kun olet valmis siirtymään tästä oppitunnista käyttöön tuotantoon allekirjoitetuilla kuiteilla varustettujen agenttien kanssa:
https://your-org.example.com/.well-known/agent-keys.json.Liity Microsoft Foundry Discordiin tavata muiden oppijoiden kanssa, osallistu toimistoaikoihin ja saa vastauksia tekoälyagentteja koskeviin kysymyksiisi.
Tämä oppitunti käsittelee yksittäisen kuitin allekirjoitusta ja hash-ketjutettuja sarjoja. Samat primitiivit kootaan useiksi edistyneemmiksi malleiksi, joita saatat kohdata, kun hallintamallisi kehittyy:
authorization_*) ja sen jälkeen (result_*) puoliksi riippumattomilla allekirjoituksilla, hyödyllistä, kun valtuutuspäätöksen ja havaitun tuloksen tekevät eri toimijat tai eri aikoina. Tämä kerrostuu additiivisesti tämän oppitunnin kuitiformaatin päälle.result_hash-kenttään. Käytännön hyötykuormat ovat usein rikkaampia kuin yhden työkalukutsun tulos: päätöstä edeltävä päättely (mallin ennuste, harkitut vaihtoehdot, todistusaineisto ja sen täydellisyys, riskin tila, vastuuketju, portin päätös) voi kaikki olla hyötykuormassa, suljettuna yhden kuitin alle. Tämä pitää kuittiformaatin minimissä ja antaa hyötykuvamalleille tilaa kehittyä toimialakohtaisesti.signature.alg voi sisältää ML-DSA-65 (NISTin jälki-kvanttiallekirjoitusstandardi) kun on aika siirtyä. Suunnittele siirtymäkausi, jolloin kuitit ovat kaksinkertaisesti allekirjoitettuja.Paikallisten tekoälyagenttien luominen
Vastuuvapauslauseke: Tämä asiakirja on käännetty käyttämällä tekoälypohjaista käännöspalvelua Co-op Translator. Vaikka pyrimme tarkkuuteen, otathan huomioon, että automaattiset käännökset saattavat sisältää virheitä tai epätarkkuuksia. Alkuperäinen asiakirja sen alkuperäiskielellä on virallinen lähde. Tärkeissä asioissa suositellaan ammattimaista ihmiskäännöstä. Emme ole vastuussa tämän käännöksen käytöstä aiheutuvista väärinymmärryksistä tai tulkinnoista.