Sehen Sie sich das Lektionvideo an: Sicherung von KI-Agenten mit kryptografischen Belegen
(Lektionvideo und Thumbnail werden nach dem Zusammenführen vom Microsoft-Inhaltsteam hinzugefügt und folgen dem Muster der Lektion 14 / 15.)
Diese Lektion behandelt:
Nach Abschluss dieser Lektion wissen Sie, wie Sie:
Stellen Sie sich vor, Sie haben einen KI-Agenten für Contoso Travel bereitgestellt. Der Agent liest Kundenanfragen, ruft eine Flug-API auf, um Optionen zu suchen, und bucht Plätze im Namen des Kunden. Im letzten Quartal hat der Agent 50.000 Buchungen abgewickelt.
Heute kommt ein Prüfer. Er stellt eine einfache Frage: „Zeigen Sie mir, was Ihr Agent gemacht hat.“
Sie übergeben Ihre Protokolldateien. Der Prüfer betrachtet sie und stellt die schwierigere Frage: „Woher weiß ich, dass diese Protokolle nicht bearbeitet wurden?“
Dies ist das Problem des Prüfpfads. Die meisten Agentenbereitstellungen heute verlassen sich auf:
Keines dieser Systeme kann die Frage des Prüfers beantworten, ohne dass der Prüfer jemandem vertrauen muss (Ihnen, Ihrem Cloud-Anbieter, Ihrem Datenbankanbieter). Für den internen Gebrauch ist dieses Vertrauen oft akzeptabel. Für regulierte Arbeitslasten (Finanzen, Gesundheitswesen, alles, was dem EU-KI-Gesetz unterliegt) ist es das nicht.
Kryptografische Belege lösen dieses Problem, indem sie jede Agentenaktion unabhängig verifizierbar machen. Der Prüfer muss Ihnen nicht vertrauen. Er benötigt nur Ihren öffentlichen Schlüssel und den Beleg selbst.
Ein Beleg ist ein JSON-Objekt, das aufzeichnet, was ein Agent getan hat, signiert mit einer digitalen Signatur.
flowchart LR
A[Agent ruft ein Werkzeug auf] --> B[Beleg-Nutzdaten erstellen]
B --> C[JSON nach RFC 8785 kanonisieren]
C --> D[SHA-256 Hash]
D --> E[Ed25519 signieren]
E --> F[Beleg mit Signatur]
F --> G[Prüfer verifiziert offline]
G --> H{Signatur gültig?}
H -- yes --> I[Manipulationssicherer Nachweis]
H -- no --> J[Beleg abgelehnt]
Ein minimaler Beleg sieht so aus:
{
"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..."
}
}
Drei Eigenschaften sind entscheidend:
Die Signatur. Der Beleg wird vom Gateway des Agenten mit einem Ed25519-Privatschlüssel signiert. Jeder mit dem entsprechenden öffentlichen Schlüssel kann die Signatur offline verifizieren. Jede Manipulation eines Feldes macht die Signatur ungültig.
Kanonische Kodierung. Vor dem Signieren wird der Beleg mit JSON Canonicalization Scheme (JCS, RFC 8785) serialisiert. Das stellt sicher, dass zwei Implementierungen, die den gleichen logischen Beleg erzeugen, byte-identischen Output liefern. Ohne Kanonisierung würden verschiedene JSON-Serializer unterschiedliche Signaturen für denselben Inhalt erzeugen.
Hash-Verkettung. Das Feld previous_receipt_hash verbindet jeden Beleg mit dem vorherigen. Das Entfernen oder Umordnen eines Belegs bricht jeden nachfolgenden Beleg. Manipulationen werden auf Kettenebene sichtbar, selbst wenn einzelne Signaturen umgangen werden.
Zusammen bieten diese Eigenschaften drei Garantien:
Sie benötigen keine spezielle Bibliothek, um einen Beleg zu erstellen. Die kryptografischen Primitive sind weit verbreitet und die Logik umfasst nur wenige Dutzend Zeilen Python-Code.
Die praktischen Übungen in code_samples/18-signed-receipts.ipynb führen Sie durch den gesamten Ablauf. Die Zusammenfassung:
import json
import hashlib
import base64
from nacl import signing
from jcs import canonicalize # RFC 8785 kanonisches 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()}"
# Erzeugen oder Laden eines Signierschlüssels (in der Produktion im Schlüsseltresor speichern)
signing_key = signing.SigningKey.generate()
verify_key = signing_key.verify_key
# Erstelle die Beleg-Nutzlast (noch keine Signatur)
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,
}
# Kanonisieren, hashen, signieren.
canonical_bytes = canonicalize(payload)
message_hash = hashlib.sha256(canonical_bytes).digest()
signature_bytes = signing_key.sign(message_hash).signature
# Ein strukturiertes Signaturobjekt anhängen.
receipt = {
**payload,
"signature": {
"alg": "EdDSA",
"sig": b64url_nopad(signature_bytes),
"public_key": b64url_nopad(bytes(verify_key)),
},
}
Das ist die komplette Signier-Pipeline. Die Übungen im Notebook führen Sie durch jeden Schritt.
Die Verifikation ist der umgekehrte Vorgang:
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:
# Die Signatur ist ein strukturiertes Objekt: {"alg", "sig", "public_key"}.
sig_obj = receipt.get("signature")
if not sig_obj or sig_obj.get("alg") != "EdDSA":
return False
# Rekonstruieren Sie die tatsächlich signierte Nutzlast (alles außer der Signatur).
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
Diese Funktion nimmt einen Beleg und gibt True zurück, wenn die Signatur gültig ist, sonst False. Kein Netzwerkaufruf, keine Dienstabhängigkeit, kein Vertrauen in Dritte erforderlich.
Um die Manipulationserkennung in Aktion zu sehen, erklärt das Notebook:
tool_args_hash.Dies ist der praktische Nachweis, dass Belege manipulationssicher sind: Jede Veränderung, so klein sie ist, bricht die Signatur.
Ein einzelner signierter Beleg schützt eine Aktion. Eine Kette von Belegen schützt eine Abfolge.
flowchart LR
R0[Quittung 0<br/>Genesis] --> R1[Quittung 1]
R1 --> R2[Quittung 2]
R2 --> R3[Quittung 3]
R1 -. previous_receipt_hash .-> R0
R2 -. previous_receipt_hash .-> R1
R3 -. previous_receipt_hash .-> R2
Jeder Beleg speichert den Hash des vorherigen Belegs. Um Beleg 2 unbemerkt zu entfernen, müsste ein Angreifer entweder:
previous_receipt_hash von Beleg 3 ändern (bricht die Signatur von Beleg 3), ODERWenn der private Schlüssel in einem Hardware-Schlüsselvault gespeichert ist und Sie den öffentlichen Schlüssel mit jedem Beleg veröffentlichen, ist keiner der Angriffe ohne Entdeckung möglich.
Das Notebook führt Sie durch:
previous_receipt_hash jedes Belegs dem tatsächlichen Hash des vorherigen Belegs entspricht.So erstellen Sie einen Prüfpfad, den ein externer Prüfer verifizieren kann, ohne Ihnen vertrauen zu müssen.
Dies ist der wichtigste Abschnitt dieser Lektion. Belege sind mächtig, aber ihre Macht hat Grenzen.
Belege beweisen drei Dinge:
Belege beweisen NICHT:
policy_id referenzierte Richtlinie tatsächlich evaluiert wurde oder dass sie diese Aktion erlaubt hätte, falls geprüft. Der Beleg zeichnet auf, was behauptet wurde, nicht was durchgesetzt wurde.Diese Grenze ist aus zwei Gründen wichtig:
Ein häufiger Fehler besteht darin zu denken, „wir haben Belege“ heißt „wir sind reguliert.“ Das tut es nicht. Belege sind eine Grundlage. Regulierung ist das System, das Sie darauf aufbauen.
Punkt 3 oben ist einen eigenen Abschnitt wert: Ein Aktionsbeleg sagt „dieser Schlüssel hat diesen Inhalt signiert,“ niemals „ein Mensch hat das genehmigt.“ Für risikoreiche Aktionen (Rückerstattungen, Löschungen, Überweisungen) fordern Governance-Rahmenwerke zunehmend genau diese fehlende Aussage, und sie ist mit den gleichen primitiven Standards produzierbar, die Sie in dieser Lektion bereits gebaut haben.
Das Anschlussnotebook code_samples/human-authorization-receipts.ipynb fügt eine zweite Art von Beleg hinzu, human.approval.v1, im selben Umschlag-Format wie die Belege dieser Lektion (eine typisierte Nutzlast, signiert mit Ed25519 über den kanonischen SHA-256, mit dem signature-Objekt außerhalb der signierten Bytes). Ein benannter Genehmiger signiert die vollständige kanonische Aktion und ihren Digest vor der Ausführung; der Aktionsbeleg des Agenten enthält denselben Aktionsdigest und eine parent_approval_ref, den receipt_hash der Genehmigung, nach derselben Konvention wie previous_receipt_hash in der oben gebauten Kette. Ein einziger verify_chain prüft beide Artefakte unter getrennten festen Schlüsselregistern (Genehmigerschlüssel vs Agentenschlüssel), so ist der Codepfad gemeinsam, aber die Autoritäten nie.
Die dadurch erreichte Eigenschaft, sorgfältig formuliert: Der Mensch hat genau diese Aktion genehmigt, und der Agent hat genau diese genehmigte Aktion ausgeführt. Die Abwehrmechanismen im Notebook machen diese Eigenschaft real und nicht nur behauptet:
Jeder Fehler wird mit einem eigenen Grund abgelehnt, so kann ein Prüfer beim Lesen erkennen, ob die Autorität veraltet ist oder die ausgeführte Aktion sich geändert hat. Die Regel, die das Notebook lehrt: Eine signierte Genehmigung ist für sich allein keine Autorität. Autorität existiert nur, wenn beide Belege zur Ausführungszeit noch dieselbe kanonische Aktion binden. Der Co-Signatur-Pfad im selben Internet-Draft, dem diese Lektion folgt (draft-farley-acta-signed-receipts), ist die offizielle Form dieses Musters.
Der Python-Code in dieser Lektion ist bewusst minimal gehalten, damit Sie jede Zeile lesen und genau verstehen können, was passiert. In der Produktion haben Sie zwei Optionen:
Direkt auf kryptografischen Primitiven aufbauen. Die 50 Zeilen, die Sie gesehen haben, reichen für viele Anwendungsfälle aus. PyNaCl (Ed25519) und das jcs-Paket (kanonisches JSON) sind gut gewartete und geprüfte Bibliotheken.
Eine Produktions-Belegbibliothek nutzen. Verschiedene Open-Source-Projekte implementieren dasselbe Muster mit zusätzlichen Features (Schlüsselrotation, Batch-Verifikation, JWK-Set-Verteilung, Integration mit Policy-Engines):
draft-farley-acta-signed-receipts, Revision 02), das sich aktuell im Normungsprozess befindet, mit einer gemeinsamen Konformitäts-Suite (agent-governance-testvectors), mit der unabhängige Implementierungen gegen byte-identischen kanonischen Output überkreuz verifizieren.protect-mcp (npm) und @veritasacta/verify (npm) bieten eine Node-basierte Implementierung der Belegsignierung und Offline-Verifikation, gedacht für die Einbettung jeglichen MCP-Servers mit einem manipulationssicheren Prüfpfad, einschließlich eines mitgeführten Co-Sign-Flows, bei dem eine pausierte Aktion eine Genehmigung ausgibt, die an den Aktionsdigest gebunden ist (im Desktop-Flow WebAuthn-gestützt), dasselbe Genehmigungsbeleg-Muster wie im Notebook zur menschlichen Autorisierung.pip install nobulex) bietet dasselbe Ed25519 + JCS-Signiermuster in Python mit LangChain- und CrewAI-Integrationen, inklusive veröffentlichter Kreuzvalidierungs-Testvektoren und Compliance-Mapping, beigetragen über OWASP PR #2210.Die Entscheidung zwischen einer Eigenentwicklung und einer Bibliotheksnutzung ähnelt der Entscheidung, ob man eine eigene JWT-Bibliothek schreibt oder eine erprobte nutzt: Beides ist vernünftig; die Bibliothek spart Zeit und reduziert die Angriffsoffenheit; der Eigenbau erzwingt das Verständnis jedes Primitivs. Diese Lektion lehrt den Eigenbau-Pfad, damit Sie die Grundlage für beide Optionen haben.
Testen Sie Ihr Verständnis, bevor Sie zur Übung übergehen.
1. Ein Beleg wird mit dem privaten Ed25519-Schlüssel des Agenten signiert. Der Prüfer hat nur den öffentlichen Schlüssel. Kann der Prüfer den Beleg offline verifizieren?
2. Ein Angreifer manipuliert das Feld policy_id eines Belegs, um zu behaupten, es sei durch eine permissivere Richtlinie geregelt. Die Signatur war über die ursprüngliche Nutzlast. Was passiert bei der Verifikation?
3. Warum enthält der Beleg einen tool_args_hash und result_hash anstelle der rohen Argumente und des Ergebnisses?
4. Das Feld previous_receipt_hash verknüpft jeden Beleg mit seinem Vorgänger. Wenn ein Angreifer stillschweigend einen Beleg aus der Mitte einer Kette löscht, was wird ungültig?
5. Ein Beleg wird sauber verifiziert. Beweist das, dass die Aktion des Agenten korrekt, sinnvoll oder regelkonform war?
Öffne code_samples/18-signed-receipts.ipynb und bearbeite alle vier Abschnitte:
Stretch-Challenge 1: Erweitere das Belegschema um ein zusätzliches, von dir gewähltes Feld (z.B. eine Anfrage-ID zur Nachverfolgung), aktualisiere die kanonische Signierlogik, um es einzubeziehen, und stelle sicher, dass der Beleg die Verifikation weiterhin besteht. Ändere dann das Feld nach der Signatur und stelle sicher, dass die Verifikation fehlschlägt. Das zwingt dich zu verstehen, wie jedes Byte der kanonischen Codierung zur Signatur beiträgt.
Stretch-Challenge 2: Hashe zwei deiner Belege zusammen mit SHA-256 (verkette deren kanonische Bytes in einer deterministischen Reihenfolge) und binde den resultierenden Digest als neues Feld in einen dritten Beleg ein, bevor du diesen signierst. Verifiziere, dass alle drei Belege weiterhin die Verifikation bestehen. Du hast gerade einen einstufigen Einschlussnachweis gebaut: Jeder, der den dritten Beleg besitzt, kann beweisen, dass die ersten beiden zum Zeitpunkt der Signatur existierten, ohne deren Inhalt offenlegen zu müssen. Dies ist das Muster, das selektiv offenlegende Belege im großen Maßstab verwenden (Merkle-Commitments, RFC 6962).
Kryptografische Belege geben KI-Agenten eine Prüfnachverfolgung, die:
Sie ersetzen nicht die Eingabevalidierung, Durchsetzung von Richtlinien oder Identitätsinfrastruktur. Sie sind die Grundlage für diese Schichten. Wenn du Agenten in regulierten Umgebungen, Organisations-übergreifenden Workflows oder jeder Umgebung einsetzt, in der ein zukünftiger Prüfer dir nicht vertrauen kann, machen Belege die Prüfnachverfolgung ehrlich.
Die wichtigste Erkenntnis: Belege beweisen, wer was wann gesagt hat. Sie beweisen nicht, dass das Gesagte wahr oder richtig war. Halte diese Unterscheidung fest. Das ist der Unterschied zwischen einem ehrlichen Herkunftssystem und einem irreführenden.
Wenn du bereit bist, von dieser Lektion zur Bereitstellung von belegsignierten Agenten in einer echten Umgebung überzugehen:
https://your-org.example.com/.well-known/agent-keys.json.Trete dem Microsoft Foundry Discord bei, um andere Lernende zu treffen, an Sprechstunden teilzunehmen und deine Fragen zu KI-Agenten beantwortet zu bekommen.
Diese Lektion behandelt einzelne Belegsignaturen und hash-verkettete Sequenzen. Dieselben Primitive setzen sich zu mehreren fortgeschrittenen Mustern zusammen, die du kennenlernen kannst, wenn sich deine Governance-Haltung weiterentwickelt:
authorization_*) und eine Nach-Ausführungs- (result_*) Hälfte mit unabhängigen Signaturen auf, nützlich, wenn Entscheidungsfindung und beobachtetes Ergebnis von verschiedenen Akteuren oder zu verschiedenen Zeiten erzeugt werden. Dies setzt additive auf das in dieser Lektion gelehrte Belegformat auf.result_hash legst. In der Praxis sind Nutzlasten oft komplexer als nur ein Tool-Ergebnis: Vorentscheidungsüberlegungen (Modellvorhersage, berücksichtigte Optionen, Beweise und deren Vollständigkeit, Risikoeinschätzung, Verantwortlichkeitskette, Ergebnis eines Gate) können alle in der Nutzlast leben, versiegelt durch einen einzigen Beleg. So bleibt das Belegformat minimal, während die Nutzlastschemas domänenspezifisch evolvieren können.signature.alg kann ML-DSA-65 (den NIST Post-Quantum-Signaturstandard) tragen, wenn du migrieren musst. Plane eine Übergangsphase mit doppelt signierten Belegen.Haftungsausschluss: Dieses Dokument wurde mit dem KI-Übersetzungsdienst Co-op Translator übersetzt. Obwohl wir uns um Genauigkeit bemühen, beachten Sie bitte, dass automatisierte Übersetzungen Fehler oder Ungenauigkeiten enthalten können. Das Originaldokument in seiner Ursprungssprache gilt als maßgebliche Quelle. Bei kritischen Informationen wird eine professionelle menschliche Übersetzung empfohlen. Wir übernehmen keine Haftung für Missverständnisse oder Fehlinterpretationen, die aus der Verwendung dieser Übersetzung entstehen.