7 Min. Lesezeit

Fehler bei der URL-Kodierung: Agent-API-Eingaben vor Aufrufen testen

Fehler bei der URL-Kodierung können einen Agenten zur falschen API-Route schicken oder Query-Daten verändern. Teste Pfade, Queries, Prozentsequenzen und Sonderzeichen vor dem Aufruf.

Fehler bei der URL-Kodierung: Agent-API-Eingaben vor Aufrufen testen

Eine URL ist keine harmlose Zeichenkette. Sie ist eine strukturierte Anweisung, deren Trennzeichen Host, Route, Parameternamen und Werte bestimmen. Wenn ein Agent vom Benutzer stammenden Text falsch mit einer URL verbindet, kann er einen anderen Endpunkt aufrufen als den, den ein Entwickler geprüft hat.

Ich habe erlebt, dass Teams eine Anfrage genehmigten, die im Tool-Protokoll wie GET /records/alice aussah. Später verbrachten sie einen ganzen Nachmittag damit herauszufinden, dass der Server eine Route mit einem zusätzlichen Slash, einem doppelten Query-Parameter oder einer decodierten Traversal-Sequenz erhalten hatte. Der Agent brauchte keinen exotischen Exploit. Gewöhnlicher Text wie a+b, %2F, &admin=true oder ein Name in einer nicht lateinischen Schrift reichte aus.

Fehler bei der URL-Kodierung werden leicht unterschätzt, weil ein HTTP-Client oft angeblich „die Kodierung übernimmt“. Er übernimmt einen Teil der Serialisierung, abhängig von seiner API und seinen Standardeinstellungen. Er kann aber nicht entscheiden, ob ein Benutzerwert in ein Pfadsegment, einen Query-Wert, einen Formular-Body oder überhaupt nicht in die Anfrage gehört. Diese Entscheidung muss in der Aktionsdefinition und in den Tests stehen.

Das Anfrageziel, nicht die sichtbare Zeichenkette, bestimmt den Aufruf

Eine Anfrage kann an jeder Stelle ihre Bedeutung ändern, an der Software die URL parst oder neu zusammensetzt. Die Zeichenfolge, die ein Agent erzeugt, ist nur der Anfang. Deine Client-Bibliothek kann sie normalisieren, ein Reverse Proxy kann sie umschreiben und das Anwendungs-Framework kann sie vor dem Routing oder der Parameterbindung decodieren.

RFC 3986 teilt eine URI in Schema, Authority, Pfad, Query und Fragment. Innerhalb eines Pfads ist / ein Trennzeichen. In einem Query erhalten & und = nach gängigen Konventionen eine Bedeutung, obwohl RFC 3986 keine allgemeine Query-Grammatik definiert. Dieser Unterschied erklärt die meisten Fehler, die pauschal als „Kodierungsprobleme“ bezeichnet werden.

Betrachte eine Aktion, die ein einzelnes Projekt laden soll:

GET https://api.example.test/projects/{project_id}

Wenn project_id den Wert north/ops hat, sind diese Anfrageziele nicht gleichwertig:

/projects/north/ops
/projects/north%2Fops

Das erste enthält nach projects zwei Pfadsegmente. Das zweite versucht, einen Literal-Slash in einem Segment zu übertragen. Ob die zweite Form erhalten bleibt, hängt vom gesamten Weg zwischen Client und Anwendung ab. Manche Stacks decodieren %2F vor dem Routing und machen daraus die erste Form. Andere lehnen sie ab. Ein Client-Test, der nur feststellt, dass „die URL kodiert wurde“, beweist daher wenig.

Dasselbe Problem tritt bei Queries auf. Eine Aktion, die nach einer wörtlichen Phrase suchen soll, darf nicht einfach diese Vorlage verwenden:

/search?q=USER_TEXT

und USER_TEXT durch Rohtext ersetzen. Bei red&limit=500 kann das Ziel so aussehen:

/search?q=red&limit=500

Die Anwendung sieht nun zwei Query-Parameter. Erstellt der Code dagegen ein Query-Objekt und übergibt red&limit=500 als Wert von q, sollte er Folgendes erzeugen:

/search?q=red%26limit%3D500

Genau diese Grenze muss getestet werden: semantisches Feld hinein, exaktes Anfrageziel heraus, geparstes semantisches Feld am Ziel.

Teste nicht nur mit Buchstaben und Zahlen. Solche Werte verbergen genau die Fehler, die Agenten sichtbar machen. Ein Agent erhält Support-Tickets, Titel von Issues, Branch-Namen, Dateipfade, kopierte URLs und freie Texte. Echte Eingaben enthalten Trennzeichen.

Ein Pfadparameter ist ein Segment, keine unfertige URL

Behandle einen Pfadparameter als einzelnes Segment, sofern der API-Vertrag nicht ausdrücklich einen Pfad vorsieht. Diese eine Regel beseitigt erstaunlich viel Mehrdeutigkeit.

Entwickler hängen Pfade oft zusammen, weil das gut lesbar wirkt:

const target = base + "/projects/" + projectId + "/builds";

Dieser Code weist projectId keine komponentenspezifische Bedeutung zu. Enthält der Wert /, ?, # oder %, hängt das Ergebnis davon ab, was später mit target geschieht. Außerdem lädt er zu einem zweiten Fehler ein: Jemand sieht einen kodierten Wert im Log, ruft „vorsichtshalber“ noch einmal encodeURIComponent auf und erzeugt so eine andere Kennung.

Baue Segmente als Daten, kodiere jedes Segment genau einmal und verbinde nur die Trennzeichen, die zur Route gehören. In JavaScript macht diese kleine Hilfsfunktion den Vertrag sichtbar:

function pathSegment(value) {
  if (typeof value !== "string" || value.length === 0) {
    throw new Error("project id must be a nonempty string");
  }
  return encodeURIComponent(value);
}

const path = "/projects/" + pathSegment(projectId) + "/builds";

encodeURIComponent passt hier, weil es /, ?, #, & und = kodiert, die sonst den Pfad verändern oder einen Query-String beziehungsweise ein Fragment beginnen würden. Eine kleine RFC-3986-Menge, darunter Apostrophe und Klammern, bleibt jedoch unescaped. Das ändert normalerweise nicht die Pfadstruktur, aber ein strenger API-Vertrag kann eine engere Kodierung verlangen. Entscheide das anhand der API-Spezifikation, nicht aus Gewohnheit.

Verwende encodeURI nicht für ein einzelnes Segment. Die Funktion erhält URI-Trennzeichen, weil sie eine vollständige URI erwartet. Übergibst du ihr north/ops, bleibt der Slash erhalten und die Route ändert sich. Die Empfehlung ist beliebt, weil der Funktionsname passend klingt. Ihr Anwendungsbereich ist hier falsch.

Ein Pfad kann durchaus mehrere Segmente enthalten, etwa bei /{owner}/{repository}. Modellier das als zwei Felder, nicht als eine freie Zeichenkette resourcePath. Wenn ein Endpunkt wirklich eine undurchsichtige Kennung mit Slashes braucht, kann ein Query-Parameter oder JSON-Request-Body die bessere Lösung sein. APIs, die undurchsichtigen Text durch Routing-Schichten zwingen, überlassen allen Beteiligten das Raten über kodierte Slashes.

Es gibt außerdem eine Routing-Entscheidung, die der Client nicht reparieren kann. Viele Proxies und Frameworks normalisieren Punktsegmente wie . und .., fassen doppelte Slashes zusammen oder lehnen kodierte Trennzeichen ab. Frage den Betreiber des Endpunkts direkt: Findet das Routing vor oder nach dem Decodieren von Prozentsequenzen statt? Teste anschließend die bereitgestellte Route einschließlich Proxy. Die Dokumentation eines Frameworks, das allein auf dem Entwicklerrechner läuft, beantwortet diese Frage nicht.

Query-Strings brauchen eine festgelegte Grammatik

Ein Query-String ist kein einziger escapeter Block. Er besteht aus Feldern, deren Grammatik zur API gehört. Vor einem sicheren Aufruf durch einen Agenten musst du wiederholte Namen, leere Werte, Arrays, Boolesche Werte, Leerzeichen und den Umgang mit Duplikaten festlegen.

Der WHATWG-URL-Standard und browserorientierte APIs verwenden bei URLSearchParams eine formularartige Query-Serialisierung. In dieser Konvention wird ein Leerzeichen oft zu +, während ein Literal-Plus zu %2B wird. Viele Server-Parser arbeiten genauso. RFC 3986 selbst sagt für eine allgemeine URI nicht, dass + ein Leerzeichen bedeutet. Wenn eine Komponente einen allgemeinen Parser und eine andere einen Formularparser verwendet, sind beide Tatsachen wichtig.

Verwende einen Query-Builder statt Stringvorlagen:

const query = new URLSearchParams();
query.set("q", userText);
query.set("include_archived", "false");
for (const label of labels) query.append("label", label);

const url = "https://api.example.test/search?" + query.toString();

Für userText = "C++ & systems" kann die genaue Schreibweise q=C%2B%2B+%26+systems lauten. Ein Server mit Formular-Decoding sollte daraus C++ & systems wiederherstellen. Dein Regressionstest sollte den semantischen Wert der API erwarten und nicht auf %20 bestehen. %20 und + können in den anzutreffenden Query-Konventionen beide ein Leerzeichen darstellen. Ein Literal-Plus muss nach dem Parsen jedoch ein Literal-Plus bleiben.

Für wiederholte Felder braucht es eine ausdrückliche Entscheidung:

?label=bug&label=security
?label=bug,security
?label=["bug","security"]

Die erste Form enthält einen wiederholten Namen. Die zweite ist ein einzelner Wert mit Komma, sofern die API nichts anderes sagt. Die dritte sieht wie JSON aus, ist aber kein JSON, solange der Server es nicht ausdrücklich parst. Sag einem Agenten nicht einfach „übergib die Labels in der URL“ und lass das Format offen. Gib der Aktion ein Array-Argument und lass sie dieses in genau die vom Endpunkt akzeptierte Form serialisieren.

Doppelte skalare Parameter sind ein weiterer leiser Fehler. Eine Anfrage mit ?role=user&role=admin kann je nach Framework den ersten Wert, den letzten Wert, ein Array oder einen Fehler liefern. Liest eine Sicherheitsprüfung den ersten Wert, während ein nachgelagerter Dienst den letzten verwendet, entstehen widersprüchliche Entscheidungen. Lehne Duplikate für Felder, die nur einmal vorkommen dürfen, so früh wie möglich ab.

Auch Fragmente verdienen Beachtung. #section verlässt den Client normalerweise nicht als Teil einer HTTP-Anfrage. Fügt eine rohe Benutzereingabe ein # hinzu, kann ein URL-Objekt vor dem Versand alles danach entfernen. Kodiere das Zeichen innerhalb eines Pfad- oder Query-Werts, wenn es Daten ist. Verlasse dich nicht auf ein Log der ursprünglichen Zeichenkette, um zu erkennen, was den Server erreicht hat.

Prozentzeichen und die Reihenfolge des Decodierens erzeugen verschiedene Kennungen

Decodiere Prozentsequenzen einmal an einer festgelegten Grenze. Wenn zwei Komponenten dieselbe Eingabe decodieren, kann ein zunächst harmloser Wert nach der ersten Prüfung zu einem Trennzeichen werden.

Der Text %252F wird nach einem Decodiervorgang zu %2F, nach einem zweiten zu /. Das ist wichtig, wenn die Validierung zwischen diesen beiden Vorgängen stattfindet. Ein Gateway könnte einen rohen / in einer Kennung ablehnen und %252F zulassen. Eine vorgelagerte Anwendung könnte anschließend erneut decodieren und die Route aufteilen. Dasselbe Muster gilt für %252e, das zu %2e und dann zu . wird.

Unterscheide in Entwurf und Tests drei Werte:

  1. Die rohe Schreibweise auf der Leitung, etwa %252F.
  2. Den Wert nach einem Percent-Decoding, etwa %2F.
  3. Den Anwendungswert nach allen Parsern und Umschreibungen, etwa /.

Teams nennen alle drei oft „die URL“. Diese unklare Sprache führt zu schlechten Reviews, weil verschiedene Stufen verglichen werden, ohne dass es auffällt.

RFC 3986 rät URI-Erzeugern, dieselbe Zeichenkette nicht mehr als einmal zu kodieren oder zu decodieren. Das ist ein guter Grundsatz, aber noch kein Implementierungsplan. Definiere, dass deine Aktionsserialisierung dekodierte Anwendungsstrings annimmt, und lege fest, wo der Server rohe Anfragebytes akzeptiert. Alles dazwischen muss die Escapes erhalten oder Formen ablehnen, die es nicht unverändert bewahren kann.

Akzeptiere bereits kodierte Eingaben nicht aus Bequemlichkeit. Eine Agent-Anweisung wie „gib eine URL-kodierte Projekt-ID an“ zwingt das Modell zu raten, ob %2F Daten oder eine Anweisung ist. Die nächste Schicht weiß nicht, ob sie das Prozentzeichen erhalten oder zu %25 kodieren soll. Akzeptiere Klartextfelder, kodiere sie einmal in der Aktionsschicht und lehne fehlerhafte Prozentsequenzen nur dort ab, wo rohe URLs absichtlich akzeptiert werden.

Unicode bringt eine weitere Grenze hinzu. Ein URL-Client wandelt Text normalerweise in UTF-8-Bytes um und kodiert Bytes, die in der gewählten Komponente nicht direkt vorkommen dürfen. Server-Frameworks können Unicode vor der Suche nach einem Benutzer oder einer Ressource unterschiedlich normalisieren. Halte Kennungen auf Anwendungsebene in einer kanonischen Form, wenn deine Domäne das verlangt. Versuche nicht, Identität durch URL-Escaping zu lösen. Escaping überträgt Bytes, entscheidet aber nicht, ob zwei optisch ähnliche Zeichenketten dasselbe Konto bezeichnen.

Teste den gesamten Anfrageweg mit gewöhnlichen, aber schwierigen Eingaben

Anmeldedaten aus Agenten heraushalten
Sallyport führt authentifizierte HTTP- und SSH-Aktionen selbst aus und gibt Ergebnisse zurück, ohne Schlüssel offenzulegen.

Ein nützlicher Kodierungstest prüft zwei Dinge: das vom Client ausgegebene Anfrageziel und die vom Empfänger geparsten Werte. Testest du nur eine Seite, kann ein Proxy oder Framework die Bedeutung dazwischen noch ändern.

Beginne mit einem kontrollierten Echo-Handler in deiner Testumgebung. Er sollte das rohe Anfrageziel aufzeichnen, sofern die Server-Laufzeit es bereitstellt, und anschließend geparsten Pfad sowie Query-Felder zurückgeben. Halte Anmeldedaten von diesem Endpunkt fern. Seine Aufgabe ist die Serialisierung, nicht die Authentifizierung.

Dieser kleine Node-Handler zeigt die Antwortstruktur:

import http from "node:http";

http.createServer((req, res) => {
  const url = new URL(req.url, "http://local.test");
  const pairs = [...url.searchParams.entries()];
  res.setHeader("content-type", "application/json");
  res.end(JSON.stringify({
    requestTarget: req.url,
    pathname: url.pathname,
    queryPairs: pairs
  }, null, 2));
}).listen(8787);

Sende bekannte Fälle dorthin und bewahre die erwartete Ausgabe auf. Ein Query-Builder, der C++ & systems erhält, sollte genau ein q-Paar zurückgeben, dessen geparster Wert exakt C++ & systems lautet. Ein manuell gebauter Query-String verrät sich oft durch zwei Paare oder dadurch, dass Pluszeichen zu Leerzeichen werden.

{
  "requestTarget": "/search?q=C%2B%2B+%26+systems",
  "pathname": "/search",
  "queryPairs": [["q", "C++ & systems"]]
}

Deine Testsuite sollte eine kompakte Matrix abdecken, keine große Menge zufälliger Strings:

  • Leerzeichen, Literal-Plus, Prozentzeichen, Ampersand, Gleichheitszeichen, Fragezeichen und Hash.
  • Slash und kodierter Slash in einer Kennung, die ein einzelnes Segment sein soll.
  • Leere Strings, fehlende optionale Felder und wiederholte Query-Namen.
  • Einen Unicode-Wert und einen Wert, dessen Prozentsequenzen wie eine zweite Decodierstufe aussehen.
  • Eine vollständige, in ein Feld kopierte URL, das eigentlich eine Kennung erwartet.

Verwende Property-based Tests, wenn das in deinem Team bereits üblich ist. Verstecke die benannten Fälle aber nicht hinter generierten Beispielen. Sie dokumentieren, warum die Grenze existiert. Bei einer Regression ist encoded slash stays inside project_id viel nützlicher als eine Seed-Nummer.

Führe dieselben Integrationstests über den Weg aus, den der Produktionsverkehr nimmt. Ein direkter Test gegen einen Anwendungsprozess zeigt nicht, ob ein Proxy %2F ablehnt, doppelte Slashes umschreibt oder bei doppelten Query-Werten einen anderen Wert auswählt. Wenn die Produktionskante nicht lokal eingebunden werden kann, nutze eine Staging-Route mit derselben Konfiguration und mache den Test zu einem Release-Check.

Gib Agenten strukturierte Argumente, keine Freiheit zum URL-Bau

Ein Agent sollte eine Aktion auswählen und typisierte Argumente liefern. Die Implementierung der Aktion sollte HTTP-Methode, erlaubte Origin, Routenvorlage, Query-Grammatik, Header und Kodierung bestimmen. Wenn der Agent eine vollständige URL übergeben darf, werden all diese Kontrollen zu einer mehrdeutigen Zeichenkette zusammengezogen.

Ein enger Aktionsvertrag kann so aussehen:

{
  "name": "get_project_builds",
  "input": {
    "project_id": "north/ops",
    "branch": "release+candidate",
    "limit": 25
  }
}

Der Aktionscode sollte project_id als Kennung validieren, als einzelnes Pfadsegment kodieren, branch in einen Query-Builder geben, limit als Ganzzahl im erlaubten Bereich prüfen und die URL aus einer festen Origin erstellen. Das Modell muss weder ein Bearer-Token sehen noch entscheiden, wohin ein Ampersand gehört.

Diese Trennung verhindert auch Origin-Verwechslungen. Eine Zeichenkette, die mit https://other.example beginnt, gehört nicht in ein Kennungsfeld. Wenn eine Aktion tatsächlich eine vom Benutzer angegebene URL abruft, muss sie eine eigene Aktion mit schriftlich festgehaltener Allowlist, DNS- und Redirect-Regeln sowie einem klaren Zweck sein. Schmuggle keine beliebige Abruffunktion über ein Feld namens callback oder file ein.

Sei vorsichtig bei APIs, die Filtersprache in Query-Parametern akzeptieren. Ein Feld wie filter=status:open AND owner:me hat zwei Grammatiken: die URL-Serialisierung und die Filtersprache selbst. URL-Kodierung hält den Filter in einem Query-Wert. Sie macht den Filter nicht sicher. Parse oder beschränke die innere Sprache separat oder biete typisierte Filterfelder an.

Vermeide Geheimnisse in URLs. Query-Strings landen in Zugriffslogs, in bestimmten Situationen im Browserverlauf, in Telemetrie und in Fehlerberichten. Anmeldedaten gehören in den von der API vorgesehenen Autorisierungsmechanismus. Ein kodiertes API-Token wird nicht sicher, nur weil es in einem Query-String steht.

Eine Genehmigung ist nützlich, kann aber keine fehlerhafte Anfrage reparieren

Die Audit-Spur offline prüfen
Mit `sp audit verify` prüfst du die verschlüsselte Audit-Kette offline, ohne Entschlüsselungsschlüssel.

Menschliche Autorisierung und korrekte Serialisierung lösen unterschiedliche Probleme. Eine Genehmigung kann bestätigen, dass ein erkannter Agent-Prozess ein bestimmtes Geheimnis verwenden darf. Sie zeigt aber nicht, ob eine Prozentsequenz bei einem nachgelagerten Router zu einem Slash wird oder ob ein doppelter Parameter nach dem Parsen die Berechtigungen verändert.

Diese Unterscheidung ist wichtig, wenn jemand behauptet, Prompts oder Genehmigungskarten machten eine strenge Anfragekonstruktion überflüssig. Das stimmt nicht. Wer https://api.example.test/projects/%252Fadmin prüft, müsste jeden Decoder auf dem Anfrageweg gedanklich simulieren. Das ist keine angemessene Sicherheitskontrolle, besonders wenn ein Agent in einer Sitzung viele Aufrufe ausführen kann.

Setze deterministische Prüfungen vor die Genehmigungsgrenze:

  • Akzeptiere strukturierte Felder statt eines fertig zusammengesetzten Anfrageziels.
  • Fixiere Origin, Methode und Routenvorlage in der Aktionsdefinition.
  • Serialisiere jedes Pfadsegment und jeden Query-Wert genau einmal.
  • Lehne doppelte oder fehlerhafte Felder ab, die der Endpunkt nicht definiert.
  • Teste das endgültige Ziel über den bereitgestellten Anfrageweg.

Sallyport kann Anmeldedaten aus einem MCP-fähigen Agenten heraushalten und eine Genehmigung für einen Agent-Prozess oder für jede Verwendung eines ausgewählten Schlüssels verlangen. Diese menschliche Kontrolle funktioniert am besten, wenn die Aktionsschicht bereits eine eindeutige Anfrage erzeugt.

Auch Logs brauchen beide Ebenen. Zeichne die genehmigte Aktion und ihre sicheren Argumente auf und bewahre anschließend eine bereinigte Darstellung des tatsächlichen Anfrageziels sowie des HTTP-Ergebnisses auf. Bei einem sensiblen Query-Feld kannst du den Wert ausblenden, aber den Parameternamen und genug Struktur behalten, um versehentliche Duplikate zu erkennen. Protokolliere niemals Autorisierungs-Header, nur weil eine Anfrage fehlgeschlagen ist.

Routennormalisierung kann einen korrekten Client aushebeln

Den tatsächlichen Agent-Prozess genehmigen
Neue Agent-Prozesse zeigen ihre Code-Signatur, bevor du die Sitzung genehmigst.

Selbst eine perfekt serialisierte Client-Anfrage kann sich an Infrastrukturgrenzen ändern. Proxies, Load-Balancer, Web Application Firewalls und Anwendungsserver haben jeweils eigene Regeln für doppelte Slashes, Punktsegmente, kodierte Trennzeichen und ungültige Escapes. Du brauchst einen Routenvetrag für die gesamte Kette.

Angenommen, der Client sendet diesen Pfad:

/files/reports%2F2025%2Fnotes

Wenn die API eine undurchsichtige Datei-ID erwartet, lautet der gewünschte Anwendungsparameter reports/2025/notes. Ein Proxy, der vor der Weiterleitung decodiert, kann jedoch /files/reports/2025/notes senden. Ein Router für /files/:id könnte das ablehnen. Ein anderer Router könnte /files/:folder/:year/:name auswählen und einen anderen Handler aufrufen. Keines dieser Ergebnisse beweist, dass die Client-Kodierung fehlerhaft war.

Treffe für jede sensible Route eine Entscheidung. Du kannst kodierte Slashes an der Kante ablehnen und dokumentieren, dass IDs keine Slashes enthalten dürfen. Du kannst sie bis zum Handler erhalten und diese Eigenschaft testen. Oder du gestaltest den Endpunkt so um, dass undurchsichtige Daten außerhalb des Pfads liegen. Was du nicht tun solltest: das Verhalten versionsabhängigen Standardeinstellungen überlassen und es anschließend als Sicherheitsgrenze bezeichnen.

Achte auch auf Redirects. HTTP-Clients folgen ihnen möglicherweise automatisch, und eine umgeleitete URL kann einen anders normalisierten Pfad oder Query-String enthalten. Für Aktionen mit Anmeldedaten muss festgelegt sein, ob Redirects erlaubt sind, ob die Ziel-Origin übereinstimmen muss und ob Autorisierungs-Header bei einem Origin-Wechsel entfernt werden. Das ist ein eigenes Thema, trifft aber häufig im selben Anfragecode auf URL-Fehler.

Wenn du mehrere Dienste betreibst, teste Meinungsverschiedenheiten absichtlich. Sende denselben kodierten Pfad in einer Nichtproduktionsumgebung über die Kante und direkt an die Anwendung. Unterscheiden sich die geparsten Pfadwerte, behebe das, bevor du einem Agenten Zugriff auf die Route gibst. Ein geteilter Parser ist auch ohne Angreifer ein Betriebsproblem.

Eine Regressionstestsuite sollte die beabsichtigte Bedeutung bewahren

URL-Tests sollen nicht eine einzige bevorzugte Schreibweise der Escapes erzwingen. Sie sollen die Beziehung zwischen Aktionsargumenten und der serverseitigen Bedeutung einer Anfrage bewahren, auch wenn sich Bibliotheken und Infrastruktur ändern.

Schreibe Assertions auf drei Ebenen. Unit-Tests prüfen, dass ein Pfadsegment-Encoder a/b in ein einzelnes kodiertes Segment umwandelt und dass die Query-Serialisierung & innerhalb eines Werts erhält. Aktionstests erfassen Methode, Origin, Pfad und Query-Paare, die an einen Echo-Handler gesendet werden. Integrationstests laufen über eine produktionsähnliche Kante und prüfen, ob der Handler die erwartete Route und die erwarteten Parameter erhält.

Wenn ein API-Vertrag unklar ist, schreibe die Mehrdeutigkeit auf und beseitige sie. „Unterstützt Suchtext in der URL“ ist kein Vertrag. Lege fest, ob ein leeres q akzeptiert wird, ob q=a+b ein Plus oder ein Leerzeichen bedeutet, ob wiederholte tag-Werte erlaubt sind und ob %2F in IDs zulässig ist. Diese Details sind nicht nebensächlich, sobald ein Agent beliebigen menschlichen Text in Aufrufe umwandeln kann.

Überdecke einen fehlschlagenden Test nicht, indem du die Eingabe früher decodierst. Früheres Decodieren lässt den Fall oft normal aussehen und verschiebt die Mehrdeutigkeit in eine weniger sichtbare Schicht. Bewahre rohen Benutzertest als Daten, bis der komponentenspezifische Serializer ihn verarbeitet. Prüfe anschließend, was der Empfänger tatsächlich geparst hat.

Sallyports Aktivitätsjournal erleichtert den Vergleich zwischen einem genehmigten Agent-Aufruf und dem zurückgegebenen Ergebnis. Die Audit-Kette kann mit sp audit verify offline geprüft werden. Nutze diese Spur zur Untersuchung einer Abweichung, nicht als Ersatz für die Entscheidung, was dein Endpunkt akzeptiert.

Der erste Test, den ich hinzufügen würde, ist beinahe banal: eine Kennung mit /, ein Query-Wert mit + und & sowie ein Prozentzeichen, das wörtlich erhalten bleiben muss. Wenn deine Aktion für diese Eingaben nicht exakt angeben kann, was der Server erhält, ist sie noch nicht bereit, Benutzertest von einem Agenten anzunehmen.

FAQ

Wie teste ich, ob ein API-Client eine URL korrekt kodiert hat?

Teste die Bytes, die den Client verlassen, die URL, die dein Server oder Proxy erhält, und die Pfad- oder Query-Werte, die die Anwendung am Ende verwendet. Diese Werte können sich unterscheiden, weil eine Client-Bibliothek Eingaben serialisiert, ein Vermittler sie normalisiert und ein Framework sie decodiert. Ein Test, der nur den HTTP-Status prüft, übersieht die Abweichung, die den Fehler verursacht hat.

Kann ich dieselbe URL-Kodierungsfunktion für Pfade und Query-Strings verwenden?

Nein. Ein Pfadsegment bezeichnet einen Teil einer Ressourcenhierarchie, während eine Query-Komponente Paare aus Namen und Werten enthält. Ein Slash in einem Pfad hat andere Folgen als ein Slash innerhalb eines Query-Werts. Eine einzige allgemeine Escape-Funktion ist deshalb ein schlechter Vertrag.

Warum wird ein Pluszeichen in einem API-Query-String zu einem Leerzeichen?

Ein Pluszeichen hat in der allgemeinen URI-Syntax nach RFC 3986 keine besondere Bedeutung. Viele Parser für formularartige Query-Strings decodieren + trotzdem als Leerzeichen, weil sie den Konventionen von application/x-www-form-urlencoded folgen. Behandle Pluszeichen als Daten und kodiere sie als %2B, wenn ihr Literalwert erhalten bleiben muss.

Sollte ein Slash in einem Pfadparameter als %2F kodiert werden?

Normalerweise solltest du einen Slash, der zu Benutzerdaten gehört, als %2F kodieren, bevor er in ein einzelnes Pfadsegment gelangt. Prüfe anschließend, ob alle Komponenten auf dem Anfrageweg ihn unverändert weitergeben, statt ihn zu decodieren und die Route aufzuteilen. Einige Server-Stacks lehnen kodierte Slashes ab. Dann kann ein undurchsichtiger Bezeichner im Query-String oder Request-Body die bessere API-Gestaltung sein.

Sind doppelt kodierte URL-Werte gefährlich?

Das kann gefährlich sein. Ein Decoder kann %252F zunächst in %2F umwandeln, während ein zweiter Decoder daraus einen Slash macht und dadurch Routing oder Validierung verändert. Lehne unerwartete Prozentsequenzen nach einmaligem Decodieren ab und teste den gesamten Anfrageweg, statt nur einer einzelnen Komponente zu vertrauen.

Wie sollte ein Agent Arrays in einem Query-String senden?

?tag=a&tag=b ist häufig ein wiederholter Parameter, während ?tag=a,b einen Wert mit Komma darstellt, sofern die API nichts anderes festlegt. Agenten sollten die von der API vorgegebene Darstellung erhalten. Tests müssen zeigen, wie leere Werte, wiederholte Namen und die Reihenfolge beim Server ankommen.

Ist es sicher, einen KI-Agenten aus Benutzereingaben eine vollständige URL erstellen zu lassen?

Gib untrusted Text als strukturierte Tool-Argumente weiter und lass die Aktionsschicht jedes Feld entsprechend seinem Ziel serialisieren. Ein Agent sollte keine vollständige URL per Stringverkettung zusammensetzen. So kannst du eine fremde Origin, eine Userinfo-Komponente oder ein unerwartetes Fragment ablehnen, bevor eine Anfrage ausgeführt wird.

Was sollte ich bei Fehlern mit URL-Kodierung protokollieren?

Ein Log, das eine decodierte URL ausgibt, kann die kodierten Bytes verbergen, die die Anfrage verändert haben. Protokolliere eine sichere, bereinigte Darstellung des endgültigen Anfrageziels sowie die geparsten Pfad- und Query-Felder. Lege niemals Anmeldedaten in eine URL, nur um die Fehlersuche zu erleichtern.

Kann eine menschliche Genehmigung URL-Kodierungsangriffe verhindern?

Eine Genehmigung bestätigt, dass ein Prozess einen Aufruf ausführen darf. Sie zeigt aber nicht, ob %252e%252e%252f von einem Proxy zweimal decodiert wird und downstream zu einem anderen Pfad führt. Die Anfragekonstruktion braucht vor der Genehmigungsgrenze eine deterministische Validierung.

Welche Sonderzeichen gehören in Regressionstests für URL-Kodierung?

Verwende einen lokalen Echo-Endpunkt oder einen kontrollierten Testdienst und schließe Leerzeichen, Pluszeichen, Prozentzeichen, kodierte Trennzeichen, Unicode, doppelte Query-Namen und leere Werte ein. Vergleiche das rohe Anfrageziel mit den geparsten Feldern des Servers. Behalte diese Fälle als Regressionstests bei, wenn sich Client-Bibliothek, Proxy oder API-Framework ändern.

Sallyport

Sallyport führt API-Aufrufe und SSH-Befehle für Ihren KI-Agenten aus. Die Schlüssel bleiben in einem lokalen Tresor auf Ihrem Mac; Sie geben jeden Lauf frei, und jede Aktion landet in einem versiegelten Journal.

© 2026 Sallyport · Open Source unter Apache-2.0 · Oleg Sotnikov