# Wie HTTP-Request-Signaturen API-Aufrufe von KI-Agenten binden

Ein KI-Agent mit einem Bearer-Token hat praktisch dieselben Freiheiten wie jeder andere Prozess, der dieses Token lesen kann. Er kann jetzt einen erlaubten Endpunkt aufrufen, es später erneut versuchen, das Token an einen anderen Host senden, wenn der Code das zulässt, und einen Request erstellen, dessen Body nur wenig mit der Benutzeranweisung zu tun hat, die den Lauf ausgelöst hat. Der Server sieht, dass die Zugangsdaten vorhanden sind, und kaum mehr.

HTTP-Request-Signaturen verbessern diese Situation, indem sie die Autorisierung an eine bestimmte Nachricht binden. Ein gutes Design kann eine Signatur nur für `POST https://api.example.test/v1/releases/42`, nur mit dem exakten vom Agenten erstellten Body, nur für kurze Zeit und nur unter einer Signaturidentität gültig machen. Das ist eine nützliche Kontrolle. Sie ersetzt weder Autorisierung und Genehmigungen noch die Trennung von Zugangsdaten.

Teams machen dabei zwei gegensätzliche Fehler. Manche behalten Bearer-Tokens, weil Signaturen kompliziert wirken, und stellen später fest, dass ein Agent ein weitreichend berechtigtes Token überall verwenden kann, wo er ausgehende Requests senden darf. Andere signieren jeden Header, den ihre HTTP-Bibliothek erzeugt, und bauen einen so empfindlichen Verifizierer, dass gewöhnliche Proxys, Zeitabweichungen oder ein Bibliotheksupdate die Produktion lahmlegen. Das richtige Design bindet die Felder, die Bedeutung oder Ziel einer Aktion verändern, und gestaltet Frischeprüfung und Verifizierung so unkompliziert, dass sie zuverlässig betrieben werden können.

## Signaturen begrenzen eine Nachricht, während Bearer-Tokens nur den Besitz nachweisen

Ein Bearer-Token beantwortet eine Frage: Hat dieser Request ein derzeit akzeptiertes Geheimnis vorgelegt? Normalerweise bindet es das Geheimnis nicht an Methode, Ziel, Body oder Zeitpunkt des Requests. OAuth-Access-Tokens können Scopes, Audiences und Ablaufzeiten enthalten, was hilft. Wer das Token besitzt, kann jeden erlaubten Scope jedoch bis zum Ablauf verwenden.

Eine Request-Signatur beantwortet eine engere kryptografische Frage: Hat der Inhaber dieses Signaturschlüssels genau diese festgelegte Menge von Request-Komponenten autorisiert? Der Server rekonstruiert die signierte Eingabe, verifiziert sie mit dem registrierten öffentlichen Schlüssel oder einem gemeinsamen Geheimnis, prüft die Zeitgrenzen und wendet anschließend die normale Autorisierung an. Diese Reihenfolge ist wichtig. Die Signaturprüfung stellt Nachrichtenintegrität und Identität des Signierenden fest. Die Autorisierung entscheidet, ob diese Identität die Aktion ausführen darf.

Betrachte einen Deployment-Service mit einem Bearer-Token, das auf das Erstellen von Releases begrenzt ist. Ein Agent erstellt zunächst ein harmloses Staging-Release. Eine spätere Prompt Injection weist denselben Agenten an, ein Production-Release zu erstellen. Das Token lässt beide Requests durch, wenn sein Scope beide Umgebungen umfasst. Das Token durch einen signierten Request zu ersetzen, behebt diesen Autorisierungsfehler allein nicht. Darf die Signaturidentität Production-Releases erstellen, kann sie auch einen Production-Request signieren.

Signaturen geben dem Service Schutzmaßnahmen, die ein gewöhnlicher Bearer-Header nicht bietet:

- Ein abgefangener signierter Request läuft schnell ab und kann nicht unbegrenzt wiederholt werden.
- Eine kopierte Signatur lässt sich normalerweise nicht von `POST /v1/staging/releases` auf `POST /v1/production/releases` übertragen.
- Ein veränderter JSON-Body führt zu einem Verifizierungsfehler, wenn der Body-Digest signiert ist.
- Der Service kann eine Signaturzugangsdaten identifizieren, ohne sie als wiederverwendbaren Header-Wert zu akzeptieren.
- Ein Verifizierer kann genau protokollieren, welche Felder der Signierende freigegeben hat.

Beschreibe das nicht als vollständigen Ersatz für Access-Tokens. Viele Systeme verwenden beides. Ein Access-Token kann den delegierenden Benutzer oder Workload identifizieren, während eine Request-Signatur die einzelne Nachricht an eine agentenspezifische Signaturidentität bindet. In anderen Systemen authentifiziert ein signierter Request den Aufrufer direkt, und der Server leitet die Berechtigungen aus der Signaturidentität ab.

Für KI-Agenten hat dieser Unterschied eine praktische Folge: Eine Signatur macht die Aktion zu einem konkreten Objekt, das geprüft, genehmigt und protokolliert werden kann. Ein Bearer-Token erscheint meist als allgegenwärtige Fähigkeit. Diese Differenz macht eine Prüfung möglich, aber nur, wenn deine Tool-Grenze verhindert, dass der Agent das Signaturgeheimnis ausliest.

## Verwende RFC 9421 statt einer eigenen kanonischen Zeichenkette

RFC 9421, HTTP Message Signatures, definiert eine strukturierte Methode, um abgedeckte Komponenten festzulegen und eine Signatur zu übertragen. Damit entfällt das übliche private Format, bei dem eine Seite Felder mit Zeilenumbrüchen verbindet, eine andere eine URL anders normalisiert und beide die Kryptografie verantwortlich machen, wenn die Verifizierung fehlschlägt.

Der RFC trennt zwei Dinge. `Signature-Input` definiert ein Label, die abgedeckten Komponenten und Parameter wie `created`, `expires`, `nonce`, `alg` und `keyid`. `Signature` enthält unter demselben Label den erzeugten kryptografischen Wert. Der Verifizierer erstellt aus den angegebenen Komponenten und Parametern die Signaturbasis und prüft sie anschließend.

Ein kompakter Request kann so aussehen:

```http
POST /v1/releases/42?environment=staging HTTP/1.1
Host: api.example.test
Content-Type: application/json
Content-Digest: sha-256=:rPMyV6WTE4Duf0JApE9tXvDYy9EzrgFQbq3e2XTCwbs=:
Signature-Input: sig1=("@method" "@authority" "@path" "@query" "content-digest" "date");created=1735689600;expires=1735689660;keyid="agent-release-17";alg="ed25519"
Signature: sig1=:BASE64_SIGNATURE_BYTES:
Date: Wed, 01 Jan 2025 00:00:00 GMT

{"version":"2025.01.01","notes":"staging validation"}
```

Der Digest-Wert oben zeigt die Struktur auf der Leitung, ist aber kein Digest für das Beispiel-JSON. Ein produktiver Client berechnet den Digest aus exakt den Bytes, die er sendet. Wenn er das JSON nach dem Signieren ein zweites Mal serialisiert, produziert er zwangsläufig einen Fehler.

RFC 9421 ist bewusst flexibel. Das ist für Vermittler und verschiedene HTTP-Versionen hilfreich, bedeutet aber, dass dein API-Vertrag ein exaktes Profil benennen muss. Lege den erlaubten Algorithmus, die verpflichtenden abgedeckten Komponenten, die maximale Signaturdauer, das Format von `keyid`, den akzeptierten Digest-Algorithmus und die Frage fest, ob ein Nonce erforderlich ist. Sagt der Vertrag nur, dass Requests signiert werden müssen, entwickelt jeder Client eigene Annahmen.

Ed25519 ist eine sinnvolle Standardwahl, wenn dein Service öffentliche Schlüssel registrieren kann. Der Server speichert einen öffentlichen Verifizierungsschlüssel. Geht dieser öffentliche Datensatz verloren, wird dadurch kein Signaturgeheimnis offengelegt. HMAC-Signaturen können funktionieren, wenn eine vertrauenswürdige Komponente und die API ein Geheimnis teilen. Dieses Geheimnis muss dann aber auf beiden Seiten vorhanden sein. Bei Agent-Workflows erhöht das oft die Zahl der Stellen, an denen ein wiederverwendbares Geheimnis durchsickern kann.

Vermeide ein proprietäres Verfahren, sofern keine Protokollvorgabe dazu zwingt. Proprietäre Formate signieren in einem Client oft die rohe URL, in einem anderen den dekodierten Pfad und im Verifizierer eine andere Darstellung des Hosts. RFC 9421 liefert definierte Komponentenbezeichner und strukturierte Felder. Nutze sie und teste anschließend das exakte veröffentlichte Profil.

## Binde Methode, Ziel und Query ein, die die Aktion bestimmen

Ein Agent sollte jedes Request-Feld signieren, das Ziel oder Serveroperation verändert. Für die meisten API-Aufrufe ist die kleinste sinnvolle Menge `@method`, `@authority`, `@path` und `@query`. Du kannst stattdessen `@target-uri` verwenden, wenn du eine Komponente für die vollständige Ziel-URI bevorzugst. Verwende jedoch nicht beide Varianten ohne einen Grund, den deine Implementierer erklären können.

`@method` verhindert, dass jemand eine für `GET` bestimmte Signatur als `DELETE` wiederverwendet. Das klingt selbstverständlich. Dennoch lassen selbst entwickelte Verfahren diese Komponente regelmäßig aus, weil ein Entwickler annimmt, der Pfad bestimme die Operation. REST-APIs verwenden häufig denselben Pfad mit verschiedenen Methoden. Die Methode verändert die Aktion.

`@authority` bindet Host und Port. Dadurch kann eine für einen API-Ursprung ausgestellte Signatur nicht gegen einen anderen Ursprung validiert werden, der dieselben Zugangsdaten akzeptiert. Das ist in Organisationen mit Preview-, Staging- und Production-Hosts wichtig. Eine für Staging vorgesehene Signaturidentität darf nicht durch einen Agenten oder eine Weiterleitung Production-Berechtigung erhalten.

`@path` und `@query` brauchen dieselbe Sorgfalt. Viele APIs legen wichtige Parameter in den Query-String:

```http
POST /v1/invoices/817/refund?amount=2500&currency=USD
```

Deckt die Signatur nur den Pfad ab, kann ein Angreifer, der den Request während der Übertragung verändert, Betrag oder Währung ändern. Nimmt der Server `dry_run`, `environment`, `force`, `page_size`, `include_deleted` oder eine Mandantenauswahl aus der Query, gehören diese Werte zur Aktion. Signiere `@query`.

RFC 9421 definiert außerdem `@query-param`, womit ein bestimmter benannter Parameter abgedeckt werden kann. Das passt zu Protokollen, in denen einige Query-Parameter ausdrücklich außerhalb der Sicherheitsentscheidung liegen, etwa Tracing-Daten. Bei einer internen, von Agenten genutzten API ist das Signieren der gesamten Query meist weniger überraschend. Jeder Parameter wird Teil des freigegebenen Requests, und Prüfer müssen sich keine Ausnahmeliste merken.

Behandle die URL-Normalisierung nicht beiläufig. Dein Verifizierer muss die in RFC 9421 festgelegte Semantik der Komponenten und die Regeln deiner gewählten Bibliothek verwenden. Dekodiere keine Prozent-Escapes und kodiere sie nicht manuell erneut. Sortiere wiederholte Query-Parameter nicht, sofern die ausgewählte Komponentendefinition das nicht vorsieht. Ein Request-Ziel besteht aus Bytes auf der Leitung, bevor es zu einem bequemen Anwendungsobjekt wird.

Weiterleitungen brauchen eine klare Regel: Übertrage einen signierten Request nicht automatisch über eine Weiterleitung an eine andere Authority. Eine Signatur, die die ursprüngliche Authority abdeckt, muss am neuen Host fehlschlagen. Genau das ist richtig. Lass den Client die Weiterleitung empfangen, eine ausdrückliche Allowlist anwenden, einen neuen Request erstellen und diesen neuen Request signieren. Bei mutierenden Requests sollten viele Teams Weiterleitungen grundsätzlich ablehnen.

## Ein signierter Body braucht einen Digest, kein Vertrauen in JSON

Signiere `content-digest`, wenn der Body das Ergebnis beeinflusst. Das umfasst fast jeden JSON-Mutationsrequest, Multipart-Upload, Formularversand und Bulk-Vorgang. `content-type` zu signieren kann ebenfalls sinnvoll sein, wenn der Server dieselben Bytes je nach Medientyp unterschiedlich verarbeitet.

Die IETF definiert `Content-Digest` in RFC 9530. Der Header enthält mit der Syntax von Structured Fields einen Digest des HTTP-Nachrichteninhalts. Die Signatur deckt den Digest-Header statt eines riesigen Bodys direkt ab. Der Empfänger berechnet den Body-Digest und vergleicht ihn, bevor er die Signatur akzeptiert. So erhält die Signatur eine Darstellung des exakten Inhalts mit fester Größe.

Eine sichere Sendereihenfolge ist einfach und muss beibehalten werden:

1. Erstelle das endgültige Request-Objekt einschließlich Query-Parametern und Headern, die die Interpretation beeinflussen.
2. Serialisiere den Body einmal in Bytes und behalte diese Bytes für die Übertragung.
3. Berechne `Content-Digest` über diese Bytes.
4. Erstelle `Signature-Input` über die ausgewählten Komponenten und signiere anschließend die Signaturbasis.
5. Sende unveränderte Request-Bytes und Header.

Der häufigste Fehler ist banaler als ein kryptografischer Angriff. Eine Anwendung serialisiert ein Objekt, um den Digest zu berechnen, signiert es, und ein HTTP-Helfer serialisiert das Objekt anschließend erneut. Reihenfolge der JSON-Mitglieder, Escaping, Leerzeichen, Zahlenformatierung oder ein Zeitstempelfeld ändern sich. Der Verifizierer meldet korrekt einen Digest-Fehler. Entwickler entfernen dann den Body-Schutz, damit der Release fertig wird. Das ist die falsche Reparatur.

Übergib dem Transport einen Bytepuffer, Stream oder unveränderlichen Request-Body. Wenn Streaming einen vollständigen Digest vor der Übertragung unmöglich macht, verwende ein dafür vorgesehenes Protokoll und teste es gründlich. Lass den Body-Digest bei einer wichtigen Operation nicht einfach weg, nur weil Streaming unbequem ist.

Für Header gilt eine engere Regel. Signiere einen Header, wenn ein Empfänger oder Vermittler damit die Sicherheitsbedeutung des Requests verändern kann. `content-type` ist ein Kandidat. Ein Mandanten-Header ist ein Kandidat, wenn der Server damit ein Konto auswählt. Ein Idempotency-Header ist ein Kandidat, wenn Wiederholungen und doppelte Effekte relevant sind. Ein Diagnose-Header normalerweise nicht.

Das Signieren von `user-agent`, `accept`, Trace-IDs, Connection-Headern und jedem Header, den deine Bibliothek erzeugt, macht Clients empfindlich. Proxys können gewöhnliche Header hinzufügen, zusammenführen oder umschreiben. HTTP erlaubt solche legitimen Transformationen. Die Signatur soll semantische Änderungen zurückweisen, nicht harmlose Transportvariationen in einen Ausfall verwandeln.

## Frischefenster sollten Zeitabweichungen tolerieren, aber aufgestaute Arbeit ablehnen

Zeitbegrenzungen machen abgefangene Signaturen kurzlebig. Sie verursachen jedoch unnötige Vorfälle, wenn Teams so tun, als hätten alle Workstations, Container und VMs eine perfekte Uhr. Die Lösung ist eine begrenzte Akzeptanzregel und eine ordentliche Zeitsynchronisierung, kein zweistündiges Gnadenfenster.

Verwende `created` und `expires` in `Signature-Input`. Eine Gültigkeitsdauer von sechzig Sekunden funktioniert gut für interaktive Aktionen, wenn der Agent unmittelbar vor dem Senden signiert. Bei einem unzuverlässigen Netzwerk oder einem Workflow, der nach einem vorübergehenden Fehler erneut versucht, können einige Minuten angemessen sein. Die API sollte eine maximale Dauer dokumentieren und erzwingen. Lass Clients keinen beliebigen Ablaufzeitpunkt wählen, nur weil ihnen das Ablaufen unbequem ist.

Der Verifizierer sollte drei Fälle getrennt bewerten:

- Weise einen Request zurück, dessen `created`-Zeit zu weit in der Zukunft liegt und die kleine konfigurierte Toleranz überschreitet.
- Weise einen Request zurück, dessen `expires`-Zeit verstrichen ist.
- Weise einen Request zurück, dessen Lebensdauer, `expires - created`, das API-Maximum überschreitet, selbst wenn er noch nicht abgelaufen ist.

Ein Server kann eine etwas vor- oder nachgehende Client-Uhr akzeptieren, ohne veraltete Arbeit durchzulassen. Ein Service könnte beispielsweise eine moderate Abweichung in der Zukunft und ein kurzes Ablaufintervall erlauben. Die genauen Werte hängen davon ab, wo Clients laufen. Das Prinzip bleibt gleich: Toleranz für Zeitabweichungen ist kein Replay-Fenster, das den ganzen Nachmittag offen bleibt.

Verwende den HTTP-Header `Date` nicht als einzige Frischeprüfung. Er kann als abgedeckte Komponente für Kompatibilität und Diagnose nützlich sein. `created` und `expires` stehen jedoch direkt in den Signaturparametern und sind weniger mehrdeutig. Signierst du beides, lege fest, welche Werte der Server verwendet, wenn sie voneinander abweichen. Ein Verifizierer, der entweder den einen oder den anderen Wert akzeptiert, verschafft Angreifern einen unnötigen Vorteil.

Aufgaben in einer Agent-Warteschlange legen einen versteckten Designfehler offen. Angenommen, ein Agent erstellt um 09:00 signierte Requests, eine menschliche Genehmigung wartet bis 09:20, und ein Worker sendet den alten Request nach der Genehmigung. Der Service sollte ihn ablehnen. Nach der Genehmigung braucht die Aufgabe ein neues Signierereignis, weil die genehmigte Aktion eine aktuelle Zeit und ein aktuelles Ziel haben sollte.

Speichere bei wiederholbaren Operationen eine Idempotency-ID in einem Header oder einem signierten Body-Feld und decke sie mit der Signatur ab. Der Client kann für jeden Versuch eine neue Signatur erstellen, während der Server die logische Operation erkennt und doppelte Nebenwirkungen verhindert. Einen abgelaufenen signierten Request wiederzuverwenden ist keine Retry-Strategie.

## Nonces verhindern Replay nur, wenn der Server sie speichert

Ein kurzes Ablaufintervall begrenzt Replay, verhindert aber nicht, dass ein Angreifer einen abgefangenen Request während dieses Zeitfensters mehrfach sendet. Ob das relevant ist, hängt vom Endpunkt ab. Ein wiederholtes Lesen hat kaum Auswirkungen. Eine wiederholte Geldüberweisung, Kontolöschung oder Infrastrukturänderung kann gravierend sein.

Ein Nonce begegnet diesem Risiko, wenn der Server jeden Nonce pro Signaturidentität als einmalig behandelt. Der Client erzeugt einen unvorhersehbaren Wert, legt ihn in die Signaturparameter oder einen abgedeckten Header und der Server speichert die erfolgreiche Nutzung, bis die Signatur abläuft. Ein zweiter Request mit derselben Identität und demselben Nonce scheitert, selbst wenn seine Signatur noch gültig ist.

Das ist der Teil, den Teams auslassen, wenn sie sagen, sie verwendeten Nonces. Ein Nonce, den der Server nicht speichert, ist nur eine zusätzliche zufällige Zeichenkette. Er beweist keine Eindeutigkeit. Ein gemeinsamer Cache oder eine Datenbanktabelle braucht eine atomare Create-Operation, damit konkurrierende Replays nicht beide die Prüfung bestehen.

Verwende einen Nonce-Speicher, wenn der mögliche Replay-Schaden den Betriebsaufwand rechtfertigt. Du musst Aufbewahrungsdauer, Größenbegrenzungen, Verhalten bei Ausfällen und Partitionierung festlegen. Bewahre einen akzeptierten Nonce bis zu dem spätesten Zeitpunkt auf, an dem der Server den Request noch akzeptieren könnte. Begrenze Datensätze nach Signaturidentität und Nonce, nicht nur nach Nonce, denn verschiedene Identitäten können denselben Wert erzeugen, ohne dass daraus ein Sicherheitsproblem entsteht.

Mache einen Nonce nicht für jeden risikoarmen Aufruf mit hohem Volumen verpflichtend, nur weil das sicherer klingt. Dadurch kann ein Ausfall des Nonce-Speichers auch harmlose Lesezugriffe lahmlegen. Ein praktisches Profil könnte ihn für unumkehrbare Mutationen verlangen und sich an anderer Stelle auf kurze Ablaufzeiten und Idempotency-Kontrollen stützen. Schreibe diese Regel für jeden Endpunkt einzeln fest.

Nonce-Prüfungen ersetzen außerdem keine Idempotency. Der Nonce sagt, dass diese signierte Nachricht einmal akzeptiert werden darf. Eine Idempotency-ID sagt, dass mehrere separat signierte Wiederholungsversuche eine beabsichtigte Geschäftsoperation darstellen. Sie lösen unterschiedliche Fehlerbilder.

## Die Verifizierung muss scheitern, bevor Anwendungscode den Request sieht

Das API-Gateway oder der Einstiegspunkt der Anwendung sollte den Request verifizieren, bevor ein Route-Handler Aktionsparameter parst, einen Job startet oder nachgelagerte Services abfragt. Ein Handler, der vor der Verifizierung den Body liest und Arbeit ausführt, hat die Sicherheitseigenschaft bereits aufgegeben, die die Signatur bieten sollte.

Ein Verifizierer braucht eine vorhersehbare Reihenfolge:

1. Parse `Signature-Input` und `Signature` als Structured Fields. Weise fehlerhafte Syntax und mehrdeutige Duplikate zurück.
2. Wähle ein erlaubtes Signaturlabel und weise unbekannte Algorithmen, fehlende verpflichtende Komponenten oder verbotene Kombinationen von Komponenten zurück.
3. Löse `keyid` zu einer aktiven Signaturidentität auf und beschaffe deren Verifizierungsmaterial.
4. Rekonstruiere die Signaturbasis gemäß RFC 9421 anhand des empfangenen Requests und nicht anhand einer rekonstruierten Anwendungs-URL.
5. Prüfe die kryptografische Signatur, den Body-Digest, die Zeitgrenzen, gegebenenfalls den Nonce-Status und anschließend die Autorisierung.

Trenne kryptografische Fehler und Autorisierungsfehler in deinen Logs. Öffentliche Antworten dürfen bewusst knapp bleiben. Ein `401` oder `403` mit einem stabilen Fehlercode reicht für Aufrufer aus. Intern solltest du festhalten, ob der Service den Request wegen einer unbekannten `keyid`, einer abgelaufenen Signatur, eines ungültigen Digests, einer abweichenden Authority, eines wiederverwendeten Nonce oder fehlender Berechtigung abgewiesen hat.

Protokolliere Signatur-Bytes nicht als harmloses Debugging-Material. Signaturen mit öffentlichen Schlüsseln sind nicht auf dieselbe Weise geheim wie HMAC-Zugangsdaten. Vollständige Request-Logs enthalten jedoch häufig Autorisierungs-Header, personenbezogene Daten und Bodies. Protokolliere eine Request-ID, die Signaturidentität, die Namen der abgedeckten Komponenten, gegebenenfalls einen Digest-Wert gemäß deiner Aufbewahrungsrichtlinie und die Entscheidung. Rohdaten sollten nur im Rahmen eines bewusst eingerichteten Incident-Verfahrens erfasst werden.

Testvektoren sind wichtiger als Prosa. RFC 9421 enthält Beispiele, dein API-Profil braucht aber eigene Fixtures. Halte Requests vor, die verifiziert werden müssen, sowie Mutationen, die scheitern müssen: geänderte Methode, geänderte Query, geändertes Body-Byte, abgelaufene Signatur, zukünftiger `created`-Wert, falsche Authority, veränderte `keyid` und wiederverwendeter Nonce. Führe sie in jeder unterstützten Client-Implementierung aus.

Ein Signaturverifizierer sollte Mehrdeutigkeiten ablehnen, selbst wenn ein toleranter Parser die Absicht des Senders erraten könnte. Doppelte Header, uneinheitliche Serialisierung von Komponenten und nicht unterstützte Algorithmen sind Protokollfehler. Ein Agent braucht keinen Server, der hilfreich rät. Er braucht einen Server, der exakt ist.

## Halte Signaturmaterial aus dem Agent-Kontext heraus

Einem KI-Coding-Agenten einen privaten Signaturschlüssel oder ein HMAC-Geheimnis zu geben, zerstört einen großen Teil des Nutzens von Signaturen. Der Schlüssel kann in Tool-Ausgaben, Shell-Historien, temporären Dateien, Fehlerberichten oder in einer Eingabeaufforderung auftauchen, die den Agenten anweist, seine Umgebung auszugeben. Selbst ein gutartiger Agent hat für ein wiederverwendbares Zugangsmittel zu viele indirekte Angriffsflächen.

Stelle stattdessen eine schmale Aktionsgrenze bereit. Der Agent übergibt Methode, erlaubtes Ziel, Header und Body an eine vertrauenswürdige lokale oder entfernte Komponente. Diese Komponente prüft das erlaubte Ziel, holt bei Bedarf eine Genehmigung ein, erstellt die Liste der abgedeckten Komponenten, signiert unmittelbar vor dem Senden und gibt die Antwort zurück. Der Agent erhält weder ein Klartextgeheimnis noch einen Platzhalter, den er versehentlich weiterleiten kann.

Diese Grenze macht auch die Prüfung von Berechtigungen konkret. Eine Signaturidentität kann auf einen Service, eine Umgebung, eine Routenfamilie und eine Aktionsklasse beschränkt werden. Wenn der Agent nur ein Staging-Release öffnen muss, gib ihm keine Zugangsdaten, mit denen er Abrechnungsänderungen oder Löschaufrufe in Production signieren kann. Die serverseitige Autorisierung bleibt dafür verantwortlich, diese Grenzen nach der Signaturprüfung durchzusetzen.

Sallyport folgt bei HTTP-Aktionen dieser Trennung: Die App verwahrt API-Zugangsdaten in ihrem verschlüsselten Tresor und führt den HTTP-Aufruf selbst aus. Ein MCP-fähiger Agent erhält dadurch das Ergebnis statt der Zugangsdaten im Klartext.

Verwechsle ein Aktions-Gateway nicht mit einem Standard für Request-Signaturen. RFC 9421 erklärt zwei HTTP-Parteien, wie sie ausgewählte Nachrichtenkomponenten authentifizieren. Ein Aktions-Gateway entscheidet, wo Signaturmaterial liegt, wann ein Mensch eine Genehmigung sieht und welcher Audit-Datensatz zu einem Agent-Lauf entsteht. Du kannst das eine ohne das andere verwenden. Die Kombination ist jedoch nützlich, wenn autonome Tools auf wichtige APIs zugreifen.

Wenn du einen lokalen Signierer verwendest, behandle seine lokale Schnittstelle als Autorisierungsgrenze. Binde Requests nach Möglichkeit an den aufrufenden Prozess, lehne beliebige Ziele ab und stelle sicher, dass ein Agent-Prozess nicht unbemerkt die genehmigte Sitzung eines anderen Prozesses verwenden kann. Ein lokaler Dienst, der für jedes lokale Programm jede übergebene URL signiert, hat lediglich eine Bearer-Fähigkeit hinter einen Socket verschoben.

## Genehmigungen und Signaturen beantworten unterschiedliche Fragen

Eine menschliche Genehmigung hält fest, dass jemand eine bestimmte Klasse von Agent-Aktionen erlaubt hat. Eine Request-Signatur hält fest, dass eine Signaturidentität eine definierte HTTP-Nachricht autorisiert hat. Kein Datensatz beweist den anderen, sofern dein Design beide nicht ausdrücklich miteinander verknüpft.

Zeige bei wichtigen Aufrufen in der Genehmigungsansicht die Felder, die die Signatur abdecken wird: Methode, Authority, Pfad, relevante Query-Parameter, Body-Digest oder eine lesbare Body-Zusammenfassung, Signaturidentität und Ablaufzeit. Genehmigt ein Benutzer `POST /v1/releases/42?environment=staging`, darf der Signierer später nicht über einen unsignierten Query-Parameter Production einsetzen.

Hier kann es der menschlichen Prüfung schaden, nur einen undurchsichtigen Body zu hashen. Der kryptografische Digest beweist Byte-Identität, sagt einer Person aber fast nichts. Bewahre beide Artefakte auf: eine kanonische Request-Darstellung für die Prüfung und einen Digest für die Integrität. Die Prüfansicht sollte aus exakt demselben unveränderlichen Request-Objekt entstehen, das der Signierer sendet, nicht aus einem separat gerenderten Plan.

Eine Sitzungsfreigabe kann für einen kurzen Agent-Lauf mit vielen risikoarmen Aufrufen angemessen sein. Eine Genehmigung pro Aufruf ist besser für Löschungen, externe Veröffentlichungen, finanzielle Änderungen und alle Operationen, die ein Angreifer zwischen Routineverkehr verstecken könnte. Verlange nicht für jeden Lesezugriff eine Genehmigung, nur um menschliche Kontrolle behaupten zu können. Menschen werden alles reflexartig bestätigen. So entsteht Genehmigungsmüdigkeit ohne echte Entscheidung.

Der Audit-Datensatz sollte Signaturidentität, abgedeckte Komponenten, Signaturlaufzeit, Autorisierungsentscheidung, gegebenenfalls die Referenz auf die Genehmigung, Response-Status und eine Request-ID enthalten. Ein lesbarer Audit-Trail hilft nach einem Vorfall bei einer einfachen Frage: Was hat der Agent unter wessen Autorität gesendet, und hat der Server es akzeptiert?

## Die wichtigsten Fehler sind meist ganz gewöhnliche Engineering-Fehler

Die gefährlichsten Implementierungsfehler sind keine gebrochenen elliptischen Kurven. Es sind unsignierte Felder, uneinheitliche Kanonisierung, veraltete Arbeit und Geheimnisse an Orten, die Agenten lesen können.

Ein Fehler entsteht, wenn ein Team `@method`, `@path` und `date` signiert, `@query` aber auslässt. Die Release-API akzeptiert im normalen Betrieb `?environment=staging`. Später ergänzt eine Wartungsänderung `?environment=production` am selben Endpunkt. Ein Proxy-Fehler oder eine bösartige lokale Komponente verändert den Parameter nach dem Signieren. Die Signatur bleibt gültig, der Handler sieht Production und der Audit-Datensatz behauptet irreführend, der Agent habe einen gültig signierten Request gesendet. Die Signatur tat genau das, was die Komponentenliste verlangte. Die Komponentenliste war unvollständig.

Ein weiterer Fehler entsteht, wenn Entwickler zehnminütige Signaturen akzeptieren, um Tickets wegen Zeitabweichungen zu reduzieren. Ein Agent signiert einen Lösch-Request, schreibt die vollständigen Header in ein Debug-Log und ein Entwickler kopiert das Log in ein Ticket. Jeder mit Zugriff auf dieses Ticket kann den Request den größten Teil des Arbeitstags wiederholen. Eine kurze Ablaufzeit beseitigt das ursprüngliche Leck nicht, begrenzt aber dessen Nutzen stark. Eine Nonce-Pflicht für Löschungen beseitigt das verbleibende Replay-Fenster nach der ersten Annahme.

Ein dritter Fehler betrifft gemeinsam verwendete HMAC-Zugangsdaten. Mehrere Agenten verwenden dasselbe Geheimnis, weil die Einrichtung individueller Identitäten zu aufwendig erschien. Findet ein Audit einen destruktiven Aufruf, kann das Team zwar die gemeinsame Integration identifizieren, nicht aber den Agent-Lauf, die Benutzerfreigabe oder den Prozess, von dem der Aufruf ausging. Gib unterschiedlichen Berechtigungsgrenzen unterschiedliche Signaturidentitäten. Zuordnung ist Teil der Incident-Reaktion und kein Luxus für Berichte.

Beginne mit einem mutierenden Endpunkt und schreibe das Profil vor der Auswahl einer Bibliothek. Lege erlaubte Authority, verpflichtende Komponenten, Body-Digest-Regel, Signaturdauer, Toleranz für Zeitabweichungen, Replay-Regel, Signaturalgorithmus und Zuordnung zu Berechtigungen fest. Erstelle anschließend Negativtests, die jedes abgedeckte Feld verändern. Kann ein Test ein relevantes Request-Feld ändern und trotzdem verifiziert werden, darfst du das Profil nicht ausliefern.

Ein signierter Request sollte sich aus dem richtigen Grund leicht ablehnen lassen. Dieser Anspruch führt zu begrenzten Berechtigungen, kurzlebigen Nachrichten, unveränderlichen Bodies und Logs, die zeigen, was nach einer Agent-Aktion passiert ist.
