# Sind benutzerdefinierte Authentifizierungs-Header sicher einzufügen?

Ein Gateway, das Zugangsdaten einfügt, muss einen HTTP-Header als Protokollsyntax behandeln, nicht als bequemes Zeichenfolgenfeld. Wenn ein Agent, eine Konfigurationsmaske, ein Tresorimport oder ein Template ein unerwartetes Byte in dieses Feld bringen kann, sendet das Gateway möglicherweise eine Anfrage mit einer anderen Bedeutung, als sie die Freigabemaske, der Audit-Eintrag oder der Zieldienst erkennen lässt.

Die sichere Regel ist eng gefasst: Reservieren Sie jedes Authentifizierungsfeld für das Gateway, validieren Sie die endgültigen Bytes unmittelbar vor dem Erstellen der Anfrage und weisen Sie fehlerhafte Eingaben ab, statt sie zu bereinigen. So lassen sich Zeilenumbrüche, versteckte Steuerzeichen, Unicode-Verwechslungen und doppelte Feldnamen erkennen, bevor Zugangsdaten den lokalen Speicher verlassen.

## Die Injektionsgrenze braucht einen Byte-Vertrag

Ein benutzerdefinierter Authentifizierungs-Header sollte einem strengeren Vertrag folgen als die allgemeine HTTP-Analyse. Allgemeine Parser müssen das große und unübersichtliche Internet unterstützen. Ein Gateway, das ein Geheimnis aus einem Tresor in eine Anfrage überträgt, hat eine kleinere Aufgabe und sollte deshalb weniger akzeptieren.

Beginnen Sie damit, vier Dinge zu trennen, die Teams oft unter einem einzigen «Header-Wert» zusammenfassen:

1. Den konfigurierten Feldnamen, etwa `X-Api-Key`.
2. Die für dieses Feld gespeicherten Geheimnis-Bytes.
3. Die vom Agenten gelieferten Anfrage-Header für eine bestimmte Aktion.
4. Die endgültige Liste ausgehender Header, die an den HTTP-Client übergeben wird.

Jedes dieser Elemente hat einen anderen Besitzer. Ein Administrator oder Entwickler konfiguriert den Namen. Der Tresor besitzt das Geheimnis. Der Agent kann eine HTTP-Aktion anfordern und gewöhnliche Anwendungs-Header liefern. Nur das Gateway setzt das geschützte Feld endgültig zusammen.

Diese Unterscheidung ist wichtig, weil ein Agent niemals ein Geheimnis erhalten sollte, nur um es mit einer Header-Bezeichnung zu verketten. Sie verhindert außerdem einen subtileren Fehler: Der Agent darf nicht `x-api-key` liefern, während das Gateway später `X-Api-Key` hinzufügt. HTTP-Feldnamen unterscheiden nicht zwischen Groß- und Kleinschreibung. Es handelt sich also um konkurrierende Instanzen desselben Feldes, nicht um zwei unabhängige Header. RFC 9110 definiert Feldnamen als nicht groß-/kleinschreibungssensitiv und beschreibt Felder, die genau ein Element erwarten, als Singleton-Felder.

Legen Sie für einen Zugangsdaten-Header den Byte-Vertrag ausdrücklich fest:

- Der Name verwendet ausschließlich Zeichen aus dem HTTP-Token-Zeichensatz und wird für Vergleiche in kanonischer Kleinschreibung gespeichert.
- Der Wert ist eine nicht leere Folge druckbarer ASCII-Bytes von `0x21` bis `0x7e`.
- Der Wert enthält kein Leerzeichen, keinen Tabulator, kein CR, kein LF, kein NUL und kein anderes Steuerzeichen.
- Das Gateway fügt genau eine Instanz des geschützten Namens hinzu.
- Eine Agentenanfrage, die das geschützte Feld nennt, wird abgewiesen. Sie wird nicht stillschweigend bearbeitet.

Diese Richtlinie weist bewusst Inhalte zurück, die in allgemeinen HTTP-Feldern zulässig sein können. Genau darum geht es. Ein API-Schlüssel, ein Bearer-Token oder eine Anbieter-Zugangsdaten sollte keinen Tabulator, kein führendes Leerzeichen und kein Zeichen mit Akzent benötigen, um sicher in einem benutzerdefinierten Header übertragen zu werden. Wenn ein Anbieter ein Format mit beliebigen Bytes verlangt, kodieren Sie es vor der Speicherung mit der dokumentierten Transportdarstellung des Anbieters. Base64url ist üblich, wenn ein Protokoll ein druckbares Token verlangt. Erfinden Sie im Gateway keine verlustbehaftete Umwandlung.

Die verlockendste Alternative besteht darin, beliebigen Text zu akzeptieren, ihn zu trimmen, Steuerzeichen durch Leerzeichen zu ersetzen und darauf zu vertrauen, dass die HTTP-Bibliothek den Rest ablehnt. Dadurch entstehen mehrere Darstellungen derselben Zugangsdaten. Die Benutzeroberfläche kann eine Zeichenfolge anzeigen, das Log eine andere enthalten und die Bibliothek eine dritte übertragen. Eine Sicherheitskontrolle sollte einmal entscheiden, ob eine Aktion gültig ist. Sie sollte die Aktion nicht in etwas anderes umschreiben.

## CR, LF und NUL müssen vor dem Erstellen der Anfrage scheitern

Weisen Sie Wagenrücklauf (`0x0d`), Zeilenumbruch (`0x0a`) und NUL (`0x00`) überall in einem geschützten Header-Wert zurück. Ein einzelnes CR oder LF muss genauso strikt abgewiesen werden wie die bekannte CRLF-Folge.

HTTP/1.1 verwendet CRLF, um Feldzeilen zu begrenzen. RFC 9112 erlaubt Empfängern unter bestimmten Umständen außerdem, ein einzelnes LF zu erkennen. Gerade deshalb darf ein ausgehendes Gateway nicht annehmen, dass alle nachgelagerten Komponenten gleich reagieren. Die Spezifikation besagt, dass Sender kein einzelnes CR innerhalb von Protokollelementen erzeugen dürfen, und sie erklärt historische gefaltete Feldzeilen für veraltet.

RFC 9110 formuliert es bei Feldwerten noch deutlicher: CR, LF und NUL sind ungültig und gefährlich, weil Implementierungen sie unterschiedlich analysieren können. Empfänger sollen sie zurückweisen oder vor der weiteren Verarbeitung durch Leerzeichen ersetzen. Das Ersetzen ist eine Wiederherstellungsregel für Empfänger, kein gutes Gateway-Design. Ein Gateway weiß, dass es eine neue Anfrage erstellt. Es sollte daher zurückweisen, statt Mehrdeutigkeit zu übernehmen.

Betrachten Sie einen Wert, der den Anfrage-Builder so erreicht:

```text
team-secret\\r\\nX-Approval: bypassed
```

Ein korrekter Validator erkennt zwei verbotene Bytes und verweigert die Aktion. Ein schwacher Validator, der nur nach den wörtlichen Zeichen `\\r\\n` sucht, sieht harmlose umgekehrte Schrägstriche. Ein Validator, der vor der Template-Auswertung läuft, prüft möglicherweise `${TOKEN}` und nie den expandierten Wert. Ein Validator, der den Zeilenumbruch durch ein Leerzeichen ersetzt, macht aus einer offensichtlichen Ablehnung eine Anfrage mit fehlerhaften, veränderten Zugangsdaten.

Die einzige sinnvolle Prüfung arbeitet auf der endgültigen Bytefolge, nach Dekodierung und Interpolation und bevor die HTTP-Bibliothek Header akzeptiert. Das Ergebnis sollte etwa so aussehen:

```text
reject header value: field=x-api-key reason=forbidden-byte byte=0x0a offset=11
```

Diese Meldung gehört in den lokalen Aktionsdatensatz, nicht zu einem externen Aufrufer. Sie nennt das konfigurierte Feld und das fehlerhafte Byte, ohne den Wert zu kopieren. Vermeiden Sie eine protokollierte Darstellung der Zugangsdaten in Anführungszeichen, als JSON-Escape, Base64 oder normalisierte Form. Auch diese Darstellungen enthalten weiterhin geheimes Material und bleiben oft länger in Logs erhalten als die Anfrage selbst.

Beschränken Sie diese Regel nicht auf HTTP/1.1. HTTP/2 überträgt Felder in komprimierten Blöcken statt in Textzeilen, verbietet NUL, LF und CR an jeder Position eines Feldwerts aber weiterhin gemäß RFC 9113. Die Spezifikation warnt ausdrücklich, dass ungeprüfte Felder Request-Smuggling verursachen können, wenn ein Vermittler sie in HTTP/1.1 übersetzt. HTTP/3 weist ebenfalls auf Felder hin, die später ein textbasiertes Protokoll durchqueren.

## Header-Namen brauchen ASCII-Regeln für den Besitz

Weisen Sie Nicht-ASCII-Header-Namen zurück. Normalisieren oder transliterieren Sie sie nicht und versuchen Sie nicht zu entscheiden, ob eine ähnlich aussehende Schreibweise «nah genug» an einem geschützten Namen liegt.

HTTP-Feldnamen sind Tokens. Die allgemeine Regel schließt Leerzeichen, Steuerzeichen, Trennzeichen und Nicht-ASCII-Zeichen aus. HTTP/2 verlangt zusätzlich kleingeschriebene Namen und weist nicht sichtbares ASCII, Großbuchstaben und Bytes über `0x7f` zurück. Ein Gateway kann eine noch einfachere Regel verwenden: Validieren Sie einen konfigurierten Namen als ASCII-HTTP-Token, schreiben Sie ihn nach ASCII-Regeln klein und behalten Sie die ursprüngliche Schreibweise nur für die Anzeige.

Der Vergleich muss bytebasiert erfolgen. Wenn der geschützte Name `x-api-key` lautet, müssen die folgenden vom Agenten gelieferten Namen nach der ASCII-Kleinschreibung alle mit ihm kollidieren:

```text
X-Api-Key
x-api-key
X-API-KEY
```

Die folgenden Namen müssen die Namensvalidierung direkt nicht bestehen und dürfen nicht repariert werden:

```text
x-api‐key       // Unicode hyphen
x-api-kеy       // Cyrillic e
x-api-key\n
x api key
```

Der angezeigte Kommentar in diesem Beispiel ist wichtig. Ein Mensch erkennt möglicherweise keinen Unterschied zwischen einem ASCII-Bindestrich und einem Unicode-Bindestrich oder zwischen einem ASCII-`e` und einem kyrillischen `е`. Ein Parser sollte nicht erst gute Typografie-Erkennung lernen müssen. Lehnen Sie alle Nicht-ASCII-Header-Namen ab, dann verschwindet die Mehrdeutigkeit.

Besitz und Syntax sind getrennte Fragen. Ein Name kann syntaktisch gültig und trotzdem verboten sein, weil das Gateway ihn besitzt. Halten Sie eine Menge geschützter Namen in kleingeschriebenem ASCII vor. Prüfen Sie jeden vom Agenten gelieferten Header gegen diese Menge, bevor Sie Header-Sammlungen zusammenführen. Erstellen Sie die ausgehende Liste anschließend von Grund auf:

```text
ordinary agent headers that passed validation
+ gateway owned credential header
+ gateway owned request metadata, if any
```

Beginnen Sie nicht mit der Liste des Agenten und überschreiben Sie ausgewählte Einträge. Manche HTTP-Bibliotheken bewahren wiederholte Werte auf, manche fassen sie zusammen und manche stellen Header als Map dar, wodurch die ursprüngliche Duplizierung verloren geht. Sobald ein geschütztes Feld in die falsche Sammlung gelangt ist, ist es zu spät, einem beiläufigen Überschreiben zu vertrauen.

## Unicode-Normalisierung ist keine Reparatur

Normalisieren Sie Authentifizierungswerte beim Einfügen nicht per Unicode. Normalisierung kann in Systemen eine legitime Rolle spielen, die Textgleichheit definieren. Ein Geheimnis ist jedoch normalerweise eine undurchsichtige Bytefolge, deren Bedeutung der Aussteller festlegt.

Die Unicode-Normalisierungsformen aus Unicode Standard Annex #15 beschreiben Umwandlungen zwischen kanonisch oder kompatibel äquivalenten Textdarstellungen. Das macht sie nicht zu sicheren Umwandlungen für Zugangsdaten. Die Zeichenfolgen `café` und `café` können gleich aussehen, obwohl sie unterschiedliche Codepunktfolgen verwenden. Ein Anbieter kann die eine ablehnen, die andere akzeptieren, eine davon hashen oder beide als unterschiedliche Geheimniswerte behandeln. Das Gateway kann nicht erraten, welches Verhalten der Anbieter gewählt hat.

Es gibt zwei getrennte Fragen zur Normalisierung:

### Identitätsfelder nur normalisieren, wenn ihr Protokoll dies definiert

Ein Produkt kann festlegen, wie es Benutzernamen, Anzeigebezeichnungen oder Anwendungsmetadaten vergleicht. Wenden Sie diese Regel an der Grenze an, an der das Produkt die Bedeutung besitzt, und bewahren Sie eine klare Aufzeichnung der gewählten Darstellung. Verwenden Sie dieselbe Regel nicht für HTTP-Zugangsdaten, nur weil beide Eingaben als Zeichenfolgen eingegangen sind.

Bei Header-Namen ist die Sache einfacher. Sie sind Protokollbezeichner, keine Alltagstexte für Benutzer. Lehnen Sie Nicht-ASCII-Eingaben ab und verwenden Sie ASCII-Kleinschreibung für den Vergleich. NFC, NFD, NFKC, NFKD, Unicode-Groß-/Kleinschreibungsfaltung und Confusable-Skelette gehören nicht in diese Entscheidung.

### Verwenden Sie niemals Confusable-Matching, um geschützte Header zusammenzuführen

Unicode Technical Standard #39 stellt Daten zur Erkennung ähnlich aussehender Zeichen für Sicherheitsprüfungen bereit. Er sagt ausdrücklich, dass Confusable-Skelettabbildungen nicht zu einer Normalisierung von Bezeichnern werden sollen. Diese Warnung ist richtig: Eine Abbildung, die beim Erkennen einer verdächtigen Bezeichnung hilft, ist keine sichere Regel für das stille Ändern von Protokolleingaben.

Sie können in einer Konfigurationsoberfläche vor einer ungewöhnlichen Bezeichnung warnen, die ein Mensch eingegeben hat. Verwenden Sie diese Erkennung aber nicht im Anfragepfad. Dort sollte die Entscheidung lauten: Dieser Feldname ist ASCII und reserviert, oder er ist ungültig. Dieser Wert besteht aus druckbarem ASCII und ist exakt, oder er ist ungültig.

Tests zur Unicode-Normalisierung bleiben auch bei einer ASCII-Richtlinie für Zugangsdaten notwendig. Sie machen versteckte Umwandlungen in Oberflächen und Speicherschichten sichtbar. Führen Sie einen zerlegten Wert, ein zusammengesetztes Äquivalent, ein geschütztes Leerzeichen, ein unsichtbares Zeichen und ein Steuerzeichen für die Schreibrichtung über jeden Eingabepfad. Das korrekte Ergebnis für einen benutzerdefinierten Authentifizierungswert ist die Ablehnung mit derselben allgemeinen Kategorie: Nicht-ASCII-Byte oder -Zeichen. Das Ergebnis darf nicht davon abhängen, ob der Text aus einer Einstellungsmaske, einer importierten Datei oder einem Agentenargument stammt.

## Doppelte Felder sind ein Autorisierungsfehler

Bei einem geschützten Authentifizierungsnamen sollte ein doppeltes Feld die Aktion abweisen, selbst wenn beide Werte identisch sind. Ein einziger Feldbesitzer ist leichter zu prüfen, leichter freizugeben und deutlich weniger vom Verhalten des Zielsystems abhängig.

Oft wird argumentiert, Duplikate seien harmlos, wenn die Werte gleich sind. Das ist Datenbereinigung, keine Autorisierung. Ein Duplikat kann vor oder nach einer Neuanordnung durch einen Proxy auftreten. Ein Zielsystem kann die erste oder letzte Instanz auswählen, Instanzen zusammenführen, die Anfrage ablehnen oder eine feldspezifische Regel anwenden. Ein Vermittler kann anders entscheiden. Die Freigabe beschreibt dann keine eindeutig bestimmte Anfrage mehr.

Lösen Sie das nicht mit der Annahme, `Authorization` sei etwas Besonderes, während jeder `X-...`-Header beliebig behandelt werden könne. Ein Anbieter kann sein benutzerdefiniertes Zugangsdatenfeld als Einzelwert definieren, und die meisten Authentifizierungsschemata tun genau das. Das Gateway sollte pro Verbindung oder Zugangsdatenbindung eine ausdrückliche Liste geschützter Namen führen. Sie kann `authorization`, `x-api-key`, `x-api-token` oder ein vom Entwickler konfiguriertes Anbieterfeld enthalten. Sie sollte nicht von einer Namenskonvention abhängen.

Die Erkennung von Duplikaten muss erfolgen, bevor die HTTP-Client-Bibliothek eine Header-Liste in ihre eigene Darstellung überführt. Viele Komfort-APIs verwenden eine Map aus einem nicht groß-/kleinschreibungssensitiven Namen zu einer Zeichenfolgenliste. Das kann Duplikate bei sorgfältiger Nutzung bewahren, aber Reihenfolge und Besitzquelle verschleiern. Andere APIs bieten eine `set`-Methode zum Ersetzen eines Wertes und eine `add`-Methode zum Anhängen eines weiteren. Diese Operationen sind erst dann sicher, wenn das Gateway Agentenversuche, geschützte Namen zu verwenden, abgewiesen hat.

Verwenden Sie für jeden vom Agenten gelieferten Header diese Entscheidungstabelle:

| Bedingung | Ergebnis des Gateways |
| --- | --- |
| Ungültiger Feldname | Aktion abweisen |
| Geschützter Name in beliebiger ASCII-Schreibweise | Aktion abweisen |
| Doppelte gewöhnliche Namen, die das Zielprotokoll erlaubt | Nur nach einer ausdrücklichen Regel pro Name beibehalten |
| Doppelte gewöhnliche Namen mit unbekannter Bedeutung | Aktion abweisen oder eine verbindungsspezifische Regel verlangen |
| Zugangsdatenfeld des Gateways | Genau einmal hinzufügen, nachdem die Agenten-Header validiert wurden |

Die dritte Zeile ist bewusst eng gefasst. `Accept` kann Listensemantik besitzen. Ein benutzerdefiniertes Anwendungsfeld muss das nicht. Wenn das Gateway nicht weiß, ob eine Wiederholung die Bedeutung ändert, sollte es keine Regel erfinden. Genau hier wird eine allgemeine Funktion zum «Durchreichen aller Header» stillschweigend zu einer Möglichkeit, die Absicht des Menschen zu umgehen.

## Jede Transformationsgrenze und anschließend das Endergebnis validieren

Eine einzige frühe Validierung reicht nicht aus, weil sich Anfragewerte nach der ersten Prüfung oft verändern. Jede Transformationsgrenze, an der Bytes erzeugt, dekodiert, verbunden oder ersetzt werden können, braucht eine eigene Invariante. Der endgültige Anfrage-Builder braucht zusätzlich die entscheidende Prüfung.

Ein praktischer Ablauf hat fünf Grenzen:

1. Validieren Sie bei der Konfiguration des Header-Namens die ASCII-Token-Syntax und reservieren Sie seine kleingeschriebene Form.
2. Validieren Sie beim Eingang eines Geheimnisses in den Speicher den Vertrag für Zugangsdaten und speichern Sie die exakt freigegebenen Bytes.
3. Validieren Sie bei einer Agentenaktion die Namen und Werte gewöhnlicher Anfrage-Header und weisen Sie geschützte Namen zurück.
4. Validieren Sie die Werte nach Templates, Dateizugriffen, Umgebungsvariablen und der Dekodierung strukturierter Anfragen erneut, da diese Vorgänge neue Bytes erzeugt haben können.
5. Validieren Sie unmittelbar vor dem Aufruf der HTTP-Bibliothek die vollständige Feldliste und stellen Sie sicher, dass jeder geschützte Name genau einmal vorkommt.

Die letzte Prüfung hat Autorität, weil sie das tatsächliche ausgehende Objekt sieht. Die früheren Prüfungen liefern gute Fehlermeldungen und verhindern, dass fehlerhafte Zustände ins System gelangen. Sie ersetzen die letzte Prüfung nicht.

Darum gehört die Validierung in den Kern des Gateways, nicht in eine MCP-Toolbeschreibung, einen Prompt oder eine Hilfsfunktion des Agenten. Diese Stellen können eine beabsichtigte Anfrage beschreiben. Sie können nicht garantieren, was den Socket erreicht. Das Gate, das die Zugangsdaten einfügt, muss auch die letzte Byteprüfung besitzen.

Sallyport folgt dem nützlichen Teil dieses Prinzips: Die Anwendung führt die HTTP-Zugangsdateninjektion selbst aus, während der Agent das Ergebnis statt des Geheimnisses erhält. Bei einer benutzerdefinierten Header-Zugangsdaten sollte die Aktionsebene trotzdem eine vom Agenten gelieferte Kopie des reservierten Feldes abweisen, bevor sie den Injektionspunkt erreicht.

Halten Sie Validierungsfehler deterministisch. Eine Anfrage mit einem CR an Byte 8 und einem doppelten geschützten Header sollte den ersten Fehler gemäß einer festen Reihenfolge melden, etwa ungültiger Name, Kollision mit geschütztem Namen, ungültiger Wert und anschließend falsche Anzahl. Determinismus macht Tests zuverlässig und verhindert, dass ein Angreifer über unterschiedliche Fehlermeldungen mehr über gespeicherte Zugangsdaten erfährt.

## Der Validator sollte klein genug für ein Audit sein

Ein kurzer Validator mit einem harten Vertrag ist sicherer als ein allgemeiner Bereiniger mit einer langen Ausnahmeliste. Das folgende Go-Beispiel erlaubt absichtlich nur druckbare ASCII-Bytes in einem benutzerdefinierten Authentifizierungswert. Es trimmt, normalisiert, dekodiert und verändert die Eingabe nicht.

```go
package authheader

import (
    "fmt"
    "strings"
)

func canonicalName(name string) (string, error) {
    if name == "" {
        return "", fmt.Errorf("empty field name")
    }
    for i := 0; i < len(name); i++ {
        b := name[i]
        ok := b == '!' || b == '#' || b == '$' || b == '%' || b == '&' ||
            b == '\'' || b == '*' || b == '+' || b == '-' || b == '.' ||
            b == '^' || b == '_' || b == '`' || b == '|' || b == '~' ||
            ('0' <= b && b <= '9') || ('A' <= b && b <= 'Z') ||
            ('a' <= b && b <= 'z')
        if !ok {
            return "", fmt.Errorf("invalid field-name byte 0x%02x at offset %d", b, i)
        }
    }
    return strings.ToLower(name), nil
}

func validateCredentialValue(value string) error {
    if len(value) == 0 {
        return fmt.Errorf("empty credential value")
    }
    for i := 0; i < len(value); i++ {
        b := value[i]
        if b < 0x21 || b > 0x7e {
            return fmt.Errorf("invalid credential byte 0x%02x at offset %d", b, i)
        }
    }
    return nil
}

func rejectProtected(headers [][2]string, protected map[string]struct{}) error {
    for _, h := range headers {
        name, err := canonicalName(h[0])
        if err != nil {
            return err
        }
        if _, found := protected[name]; found {
            return fmt.Errorf("agent supplied protected field %q", name)
        }
    }
    return nil
}
```

Dieses Beispiel akzeptiert `:` in einem Wert, weil druckbares ASCII dieses Zeichen einschließt. Für viele API-Tokens ist das in Ordnung. Wenn ein Zielsystem nur eine dokumentierte Teilmenge akzeptiert, setzen Sie diese Anbieterregel in einem verbindungsspezifischen Validator durch. Lassen Sie eine globale Gateway-Richtlinie nicht raten, dass ein Doppelpunkt, Schrägstrich oder Gleichheitszeichen verdächtig ist.

Die Verwendung von `string` in Go bedeutet nicht, dass der Validator Unicode-bewusst ist. Beim Indizieren eines Go-Strings erhält man Bytes. Eine mehrbyteige UTF-8-Folge enthält Bytes über `0x7e`, sodass dieser Vertrag sie sauber zurückweist. Wenn Ihre Laufzeit Unicode-Skalarwerte statt Bytezeichenfolgen speichert, kodieren Sie zuerst in die exakt ausgehende Byte-Darstellung und führen Sie dann die Bytevalidierung aus.

Der Aufrufer darf `validateCredentialValue` nicht als Bereinigungshilfe anbieten. Die einzigen gültigen Ergebnisse sind die Freigabe unveränderter Bytes oder ein Fehler. Jede Methode namens `sanitizeHeader`, `cleanHeader` oder `normalizeToken` verdient bei einer Prüfung Misstrauen, weil sie Aufrufer dazu einlädt, ein Geheimnis zu verändern und sich dabei geschützt zu fühlen.

## Eine Testmatrix braucht feindliche Darstellungen, nicht nur feindliche Zeichenfolgen

Eine Testsuite sollte beweisen, dass jeder Weg in die ausgehende Anfrage denselben endgültigen Validator erreicht. Sie sollte den Validator nicht nur direkt mit offensichtlichen CRLF-Eingaben aufrufen.

Verwenden Sie zuerst tabellengesteuerte Unit-Tests für rohe Werte:

```go
cases := []struct {
    name  string
    value string
    want  bool
}{
    {"ordinary token", "mF_9.B5f-4.1JqM", true},
    {"carriage return", "abc\rdef", false},
    {"line feed", "abc\ndef", false},
    {"crlf", "abc\r\ndef", false},
    {"nul", "abc\x00def", false},
    {"leading space", " abc", false},
    {"trailing tab", "abc\t", false},
    {"composed Unicode", "caf\u00e9", false},
    {"decomposed Unicode", "cafe\u0301", false},
}
```

Testen Sie anschließend den vollständigen Aktionspfad mit Beispielen, die für Anwendungscode harmlos wirken:

- Eine JSON-Anfrage, in der ein Zeilenumbruch durch die `\n`-Dekodierung entsteht.
- Einen Konfigurationsimport, bei dem eine Datei nach dem Token mit einem Zeilenumbruch endet.
- Ein Template-Ergebnis, bei dem eine fehlende Variable zu einer leeren Zeichenfolge wird.
- Eine Agentenanfrage mit `X-Api-Key` und `x-api-key` zugleich.
- Eine Agentenanfrage mit einer Nicht-ASCII-Verwechslung im Namen, die an der Namenssyntax scheitern muss, statt den Vergleich mit geschützten Namen zu umgehen.

Der Fall mit dem Dateiende erkennt eine verbreitete Gewohnheit. Entwickler kopieren ein Token in eine Textdatei, fügen unbemerkt einen abschließenden Zeilenumbruch hinzu und verwenden einen Befehl oder Importer, der ihn beibehält. Ein Shell-Befehl kann abschließende Zeilenumbrüche in einem Pfad entfernen, während ein Dateileser sie in einem anderen beibehält. Das korrekte Verhalten des Gateways ist einheitlich: Es trimmt nicht. Es fordert den Betreiber auf, die gespeicherten Zugangsdaten zu korrigieren.

Ergänzen Sie Property-Tests für den endgültigen Builder. Erzeugen Sie kurze Bytefolgen mit jedem Steuerzeichen, Bytes über `0x7f` und druckbarem ASCII. Stellen Sie sicher, dass nur nicht leere Zeichenfolgen bestehen, die vollständig im erlaubten Bereich liegen. Erzeugen Sie für jeden geschützten Feldnamen Varianten mit unterschiedlicher Großschreibung und prüfen Sie, dass jede ASCII-Variante den Besitz durch den Agenten abweist. So lassen sich Fehler finden, etwa die Prüfung nur der gemeinsamen Folge `\r\n`, das Vergessen eines einzelnen LF oder das Kleinschreiben erst nach der Suche in der Menge geschützter Namen.

Verwenden Sie abschließend einen Integrations-Listener, der die Header erfasst, die Ihre HTTP-Bibliothek tatsächlich erhält. Er sollte niemals einen fehlerhaften geschützten Wert sehen, weil das Gateway vorher abweisen sollte. Der Listener prüft die Erstellung, nicht die Sicherheitsrichtlinie. Wenn dieser Integrationstest ein zweites geschütztes Feld entdeckt, ist das ein Gateway-Fehler, auch wenn der Zielserver die Anfrage ohnehin abgewiesen hätte.

## Ein großzügiger Fallback verbirgt den Fehler, den Sie beheben müssen

Verbotene Bytes durch Leerzeichen zu ersetzen, Whitespace zu trimmen oder das «letzte» Duplikat zu behalten, ist beliebt, weil dadurch Demos funktionieren. Gleichzeitig wird es schwer, die Quelle einer ausgehenden Zugangsdaten zu rekonstruieren.

Gehen Sie den Trim-Fall durch. Ein Betreiber importiert `token-42\n` aus einer Datei. Ein Codepfad trimmt den Wert und sendet `token-42`. Ein anderer speichert den Rohwert und weist ihn später zurück. Nun sieht der Betreiber, dass eine Aktion in einem lokalen Test funktioniert, im Gateway aber scheitert. Irgendjemand wird schließlich Trimming im Gateway ergänzen, um die Inkonsistenz zu beseitigen. Monate später erzeugt ein Template `token-42\r\nX-Role: admin`. Derselbe Trim-Code entfernt möglicherweise nur den abschließenden Zeilenumbruch und lässt das interne CRLF bestehen. Das «hilfreiche» Verhalten hat sowohl den Quellfehler als auch die Sicherheitsgrenze verschleiert.

Die richtige Reparatur ist unspektakulär. Definieren Sie ein einziges akzeptiertes Zugangsdatenformat, weisen Sie alle anderen Werte ab und lassen Sie Importwerkzeuge anzeigen, warum die Bytes fehlschlagen. Eine Konfigurationsmaske kann `trailing LF at offset 8` anzeigen, ohne das Token offenzulegen. Ein Kommandozeilen-Importer kann dieselbe Kategorie ausgeben und mit einem Fehlercode enden. Der Benutzer korrigiert die Quelle, statt jede spätere Schicht zum Raten zu zwingen.

Audit-Einträge sollten eine Autorisierungsablehnung von einem Transportfehler unterscheiden. Erfassen Sie, dass der Agentenprozess eine Aktion angefordert hat, dass die Aktion vor dem Versand abgewiesen wurde, welche konfigurierte Zugangsdatenbindung betroffen war und welche Validierungskategorie vorlag. Rufen Sie das Ziel nicht auf und erzeugen Sie keine künstliche HTTP-Antwort, die wie eine Ablehnung durch den entfernten Dienst aussieht. Es gab keine entfernte Anfrage.

Sallyports getrennte Sitzungs- und Aktivitätsdatensätze bieten für eine solche Ablehnung einen passenden Ort: Die Sitzung zeigt, welcher Agentenlauf den Versuch unternommen hat, während der Aktionsdatensatz festhalten kann, dass die lokale Validierung den Versand verhindert hat. Der Datensatz sollte nützlich bleiben, ohne das abgewiesene Geheimnis oder eine maskierte Annäherung daran zu speichern.

## Die Regel ist streng, weil das Gateway ein Geheimnis besitzt

Ein gewöhnlicher HTTP-Client kann breite Eingaben tolerieren, weil er oft Daten sendet, die der Aufrufer bereits besitzt. Ein Zugangsdaten-Gateway hat eine andere Verantwortung. Es entscheidet, ob ein Agent eine durch ein Geheimnis geschützte Aktion auslösen darf, und muss diese Entscheidung anhand einer Anfrage treffen, deren Syntax sich nicht unbemerkt verändern kann.

Weisen Sie Steuerzeichen und Nicht-ASCII-Zeichen in benutzerdefinierten Authentifizierungswerten zurück. Reservieren Sie Authentifizierungsnamen und vergleichen Sie sie nach ASCII-Kleinschreibungsregeln. Lehnen Sie doppelte geschützte Felder ab. Normalisieren oder trimmen Sie Zugangsdaten niemals auf dem Weg nach draußen. Validieren Sie jeden Eingabepfad und anschließend ein letztes Mal die vollständige Header-Liste.

Wenn das Authentifizierungsformat eines Anbieters nicht in diesen Vertrag passt, dokumentieren Sie die anbieterspezifische Kodierung und implementieren Sie sie, bevor das Geheimnis den Anfrage-Builder erreicht. Lockern Sie das Gateway nicht und akzeptieren Sie keine mehrdeutigen Textwerte, nur weil eine Integration mit einem fehlerhaften Token eingetroffen ist. Der erste fehlerhafte Wert sollte am Gate stoppen. Die Ablehnung erklärt das Byteproblem, ohne die Zugangsdaten sichtbar zu machen.
