8 Min. Lesezeit

Vorrang von HTTP-Headern: Konflikte bei API-Identitäten verhindern

Der Vorrang von HTTP-Headern kann die API-Identität über Clients und Proxys hinweg aufteilen. Erfahre, wie du doppelte Authorization- und benutzerdefinierte Header sicher ablehnst.

Vorrang von HTTP-Headern: Konflikte bei API-Identitäten verhindern

Eine Anfrage mit zwei Zugangsdaten ist keine Anfrage mit einer Ersatzauthentifizierung. Sie ist eine mehrdeutige Anweisung an eine Kette von Software, die sie an jedem Übergang anders interpretieren kann. Ich habe erlebt, dass Teams stundenlang eine API beschuldigten, während ein Proxy unbemerkt einen Authorization-Wert auswählte und die Anwendung einen anderen. Das Symptom wirkt zufällig, bis jemand die rohen Header an jeder Grenze ausgibt.

Für den Vorrang von HTTP-Headern braucht es eine Regel, die sich in einem Satz formulieren, auf der Leitung testen und vor der Authentifizierung erzwingen lässt: Eine Anfrage mit mehr als einem Wert für dasselbe sicherheitsrelevante Zugangsdatenfeld schlägt fehl. Wähle nicht den ersten Wert. Wähle nicht den letzten. Verbinde Werte nicht mit einem Komma. Solche Entscheidungen machen zufälliges Implementierungsverhalten zu deiner Authentifizierungsrichtlinie.

Das betrifft mehr als Authorization. Viele APIs akzeptieren X-API-Key, einen benutzerdefinierten Tenant-Header, einen Zeitstempel für signierte Anfragen oder ein weitergeleitetes Identitätsfeld. Sobald Zugangsdaten Clients, Load Balancer, Protokollübersetzer und Middleware der Anwendung durchlaufen, wird der Umgang mit Duplikaten Teil der Sicherheitsgrenze.

HTTP bestimmt keinen allgemeinen Gewinner

HTTP definiert die Syntax von Feldern und spezielle Regeln zum Zusammenführen bestimmter wiederholter Felder. Es sagt jedoch nicht, dass überall das erste Authorization-Feld gewinnt oder überall das letzte. Ein Empfänger muss den empfangenen Feldbereich anhand der Semantik des Feldes und seiner eigenen Implementierung interpretieren.

RFC 9110 sagt, dass ein Empfänger mehrere Feldzeilen mit demselben Feldnamen zu einem durch Kommas getrennten Feldwert verbinden darf, wenn die Definition des Feldes eine durch Kommas getrennte Liste erlaubt. Es sagt auch, dass ein Empfänger Feldzeilen nicht verbinden darf, wenn die Felddefinition dies nicht zulässt. Diese Unterscheidung wird regelmäßig verwischt. «Header können zusammengeführt werden» ist keine Regel für jeden Header. Sie gilt für Felder, die als Listen konzipiert sind.

Accept ist ein nützlicher Vergleich. Ein Client kann mehrere Accept-Zeilen senden, und ein Empfänger kann ihre Werte im Allgemeinen als eine Liste akzeptierter Medientypen behandeln. Authorization enthält Zugangsdaten für eine Anfrage. Es ist keine allgemeine Liste austauschbarer Zugangsdaten. Ein Komma kann außerdem innerhalb der Syntax eines Authentifizierungsschemas eine Bedeutung haben. Durch das Verbinden zweier Werte kann eine Zeichenkette entstehen, die kein Client beabsichtigt hat und die verschiedene Parser unterschiedlich lesen.

Headerfeldnamen unterscheiden nicht zwischen Groß- und Kleinschreibung. Das sind Duplikate:

Authorization: Bearer token-a
authorization: Bearer token-b

Ein Detektor, der die ursprüngliche Schreibweise vergleicht, übersieht diesen Fall. Normalisiere den Namen, bevor du Werte zählst.

Verwechsle doppelte Feldzeilen nicht mit mehreren Authentifizierungsaufforderungen in WWW-Authenticate. Ein Server kann in einer Antwort mehrere akzeptierte Schemata anbieten. Das ist ein Angebot des Servers. Eine Anfrage mit zwei Authorization-Werten präsentiert konkurrierende Zugangsdaten durch den Client. Das sind unterschiedliche Probleme und sie brauchen eine unterschiedliche Behandlung.

Die gleiche Warnung gilt, wenn eine API sowohl ein standardisiertes als auch ein benutzerdefiniertes Zugangsdatenfeld unterstützt. Eine API kann absichtlich Authorization: Bearer ... oder X-API-Key: ... akzeptieren. Wenn die API-Dokumentation nicht definiert, wie beide zusammen aufgelöst werden, erzeugt das Senden beider Felder einen Identitätskonflikt. Lehne die Anfrage ab. Ein Fallback, der nur in irgendeiner Middleware existiert, ist kein Vertrag.

Clients machen doppelte Header leichter möglich als gedacht

Ob ein Client wiederholte Header ausgeben kann, hängt vom Anfragemodell der Bibliothek ab. Bibliotheken, die Header als Map anbieten, überschreiben häufig einen Wert, wenn der Code denselben Namen zweimal setzt. Bibliotheken mit einem Array oder einer Sammlung mehrerer Werte können beide senden. Keine dieser Verhaltensweisen beweist, was am nächsten Übergang ankommt.

Mit curl kannst du durch wiederholtes -H zwei Felder anfordern:

curl --http1.1 -v https://api.example.test/orders \
  -H 'Authorization: Bearer first' \
  -H 'Authorization: Bearer second'

Die ausführliche Ausgabe sollte zwei ausgehende Zeilen zeigen, etwa so:

> Authorization: Bearer first
> Authorization: Bearer second

Das beweist nur die ausgehende HTTP/1.1-Anfrage von curl auf dieser Verbindung. Es beweist nicht, dass Edge, Load Balancer oder Anwendung beide Werte empfangen haben. Teste einen kontrollierten Endpunkt, den du selbst betreibst, bevor du dieses Muster gegen eine Produktions-API verwendest. Die Tokens in Beispielen sollten wegwerfbar sein. Echte Bearer-Tokens dürfen niemals in eine Terminalaufzeichnung oder ein Support-Ticket gelangen.

In JavaScript überrascht das übliche Headers-Objekt viele Entwickler. set() ersetzt den aktuellen Wert. append() fügt konzeptionell einen weiteren Wert hinzu, doch Serialisierung und Semantik des Headers bleiben wichtig. Ein Entwickler kann glauben, zwei Header gesendet zu haben, während die Bibliothek stattdessen einen durch Kommas verbundenen Wert erzeugt hat. Genau deshalb müssen Authentifizierungstests den rohen Eingang prüfen und nicht nur ein Objekt im Speicher.

Auch Servercode in Node.js hat eine Falle. req.headers stellt normalerweise normalisierte Namen bereit und kann eine zusammengefasste Ansicht liefern. req.rawHeaders bewahrt bei HTTP/1.1-Anfragen eine wechselnde Liste empfangener Namen und Werte. Eine sichere Diagnose sollte normalisierte Namen aus der Rohdarstellung zählen und keine geheimen Werte ausgeben:

function duplicateNames(rawHeaders) {
  const counts = new Map();
  for (let i = 0; i < rawHeaders.length; i += 2) {
    const name = rawHeaders[i].toLowerCase();
    counts.set(name, (counts.get(name) || 0) + 1);
  }
  return [...counts.entries()].filter(([, count]) => count > 1);
}

console.log(duplicateNames(req.rawHeaders));
// Example output: [ [ 'authorization', 2 ] ]

Verwende das als Diagnosehilfe, nicht als Freibrief, jeden Header in der Anwendung selbst zu parsen. Dein Framework oder Gateway sollte die eigentliche Ablehnung am frühestmöglichen vertrauenswürdigen Punkt durchführen. Es geht darum sichtbar zu machen, was das bequeme Header-Objekt verborgen hat.

Benutzerdefinierte Header verdienen dieselbe Vorsicht. Ein Client kann X-API-Key durch eine Ebene für Standard-Header und eine Ebene pro Anfrage versehentlich zweimal hinzufügen. Er kann außerdem einen von einem Unternehmens-Wrapper geerbten Authorization-Wert senden, während der Code ausdrücklich einen API-Schlüssel ergänzt. In lokalen Tests funktioniert die API möglicherweise, weil der lokale Pfad den Wrapper nicht enthält. In der Produktion kommen dann beide Zugangsdaten an und die API verhält sich anders.

Proxys können Anfrage und Beweislage verändern

Ein Reverse-Proxy ist ein HTTP-Empfänger und zugleich ein neuer HTTP-Sender. Er trägt nicht bloß Bytes vom Client zur Anwendung. Er parst die eingehende Anfrage, wendet Konfiguration an, kann Protokolle übersetzen und schreibt eine neue Anfrage an den nächsten Dienst. Dadurch kann er Duplikate erhalten, verwerfen, zusammenführen oder einen neuen Zugangsdaten-Header erzeugen.

Gefährlich ist eine geteilte Interpretation. Angenommen, ein Client sendet:

Authorization: Bearer attacker-token
Authorization: Bearer service-token

Eine Edge-Komponente behält für ihre Zugriffskontrolle den ersten Wert. Die Bibliothek am nächsten Dienst stellt der Anwendung den letzten Wert bereit. Das Edge autorisiert eine Identität, während die Anwendung als eine andere arbeitet. Selbst wenn keine der Komponenten einen Parserfehler hat, besitzt die Kette keine eindeutige Bedeutung für die Anfrage.

Ein gewöhnlicherer Fehler ist weniger spektakulär und häufiger. Eine Proxy-Konfiguration fügt für einen Dienst ein Authorization-Feld mit Zugangsdaten ein, entfernt aber ein eingehendes Feld nicht. Der Zieldienst wählt einen Wert nach einem Verhalten aus, das niemand dokumentiert hat. Ein späteres Proxy-Upgrade, ein Routenwechsel oder die Umstellung von HTTP/1.1 auf HTTP/2 verändert, welcher Wert bestehen bleibt. Das Team nennt es einen sporadischen Authentifizierungsausfall, weil es die Duplizierung nie aufgezeichnet hat.

Weiterleitungsfelder erzeugen ein verwandtes Identitätsproblem. X-Forwarded-User, X-Forwarded-Client-Cert und benutzerdefinierte Identitätsheader wandern oft von einem vertrauenswürdigen Edge zur Anwendung. Das öffentlich erreichbare Edge muss vom Aufrufer gelieferte Kopien entfernen, bevor es eigene Werte hinzufügt. Leitet es nicht vertrauenswürdige Kopien weiter, kann eine Anwendung, die der falschen Position in der Liste vertraut, eine gefälschte Identität akzeptieren.

Die Regel unterscheidet sich je nach Vertrauensgrenze leicht:

  • Am öffentlichen Eingang: doppelte Authentifizierungsfelder ablehnen und vom Client gelieferte interne Identitätsheader entfernen.
  • An einem vertrauenswürdigen Gateway: nach dem Entfernen geschützter Eingaben des Aufrufers genau die für den nächsten Dienst benötigten Zugangsdaten oder Identitätsheader einsetzen.
  • In der Anwendung: Duplikate erneut ablehnen. Schutz am Eingang ist notwendig, aber Routenänderungen umgehen Annahmen irgendwann.
  • In Protokollen: Headername, Anzahl, Route und Anfragekennung erfassen. Ein Zugangsdaten-Schema nur dann protokollieren, wenn dies sicher ist.

Verlasse dich nicht ohne Test auf das Standardverhalten eines Proxys. Die Voreinstellungen unterscheiden sich nach Produkt, Modul, Protokoll und Konfiguration. Eine Einstellung für doppelte Antwort-Header sagt nichts über doppelte Zugangsdaten in Anfragen aus. Lies die Dokumentation der genauen Direktive oder Middleware und sende anschließend eine echte doppelte Anfrage durch den eingesetzten Pfad.

HTTP/2 und HTTP/3 beseitigen alte Syntax, nicht Mehrdeutigkeit

HTTP/2 und HTTP/3 senden keine textuellen Headerzeilen über die Leitung, übertragen aber weiterhin eine Folge von Headerfeldern. Die Protokollregeln verbieten doppelte Pseudo-Header wie :method und verlangen, dass diese vor normalen Feldern stehen. Das hilft bei der Protokollkorrektheit, gibt Authorization aber keinen universellen Vorrang.

Ein HTTP/2-Endpunkt kann wiederholte normale Headerfelder empfangen. Eine Bibliothek kann sie abhängig vom Feld und ihrer API als getrennte Werte, als zusammengefassten Wert oder als Fehler bereitstellen. Für HTTP/3 gilt dasselbe auf Anwendungsebene. Du musst die von deinem Edge akzeptierten Protokollversionen testen.

Bei der Protokollübersetzung werden Annahmen brüchig. Ein Client spricht HTTP/2 mit einem CDN oder Load Balancer. Das CDN spricht HTTP/1.1 mit einem Gateway. Das Gateway spricht HTTP/2 mit einem Dienst. Jeder Übergang muss eine Headerdarstellung übersetzen. Wenn der erste Übergang ein Feld zusammenfasst und der zweite es beibehält, kann die Anwendung am Ende die ursprüngliche Anfrage nicht wiederherstellen. Deshalb sollte der erste vertrauenswürdige Empfänger Mehrdeutigkeit ablehnen, statt später eine clevere Wiederherstellung zu versuchen.

HTTP/2 behandelt verbindungsspezifische Header ebenfalls anders. Felder wie Connection sind verboten, weil sie das Verbindungsverhalten von HTTP/1.1 beschreiben. Das hat nichts mit dem Vorrang von Zugangsdaten zu tun. Übertrage eine protokollspezifische Headerregel nicht einfach auf einen benutzerdefinierten Authentifizierungsheader und nehme an, er sei dadurch geschützt.

Manche Teams versuchen, das Problem durch Kleinschreibung zu lösen, weil HTTP/2 auf der Leitung kleingeschriebene Feldnamen verlangt. Das behebt nur ein triviales Problem. Auch HTTP/1.1-Namen unterscheiden nicht zwischen Groß- und Kleinschreibung, und ein Gateway kann zuerst HTTP/1.1 empfangen. Normalisiere Namen überall.

Baue deine Testmatrix um Pfade herum, nicht nur um Protokolle. Teste eine direkte Anfrage an die Anwendung in einer Testumgebung, die öffentliche Route und jede interne Route für Worker oder Bereitstellungswerkzeuge. Sende auf jeder Route doppelte Authorization-Header, doppelte benutzerdefinierte Zugangsdaten-Header und zwei konkurrierende Zugangskanäle. Das erwartete Ergebnis sollte in jedem Fall derselbe eindeutige Clientfehler sein.

First Wins und Last Wins schaffen beide eine Angriffsfläche

Freigaben für sensible Schlüssel verlangen
Markiere einen Schlüssel für die Freigabe pro Aufruf, wenn jede ausgehende Nutzung eine menschliche Entscheidung erfordert.

«Verwende den ersten Header» wirkt vorsichtig, weil es dem Lesen von links nach rechts entspricht. «Verwende den letzten Header» wirkt praktisch, weil spätere Konfiguration frühere Standardwerte überschreiben soll. Beide Regeln scheitern, weil Sender und Vermittler die Reihenfolge unterschiedlich beeinflussen können.

First Wins ist angreifbar, wenn ein Angreifer Zugangsdaten voranstellen kann, bevor eine vertrauenswürdige Komponente ihre eigenen ergänzt. Last Wins ist angreifbar, wenn ein Angreifer Zugangsdaten anhängen kann, nachdem eine vertrauenswürdige Komponente den ersten Wert geprüft hat. Der konkrete Angriff hängt von Routing und Vertrauen ab, der Designfehler bleibt gleich: Eine Komponente wählt Zugangsdaten aus, während eine andere eine andere Anfrage sieht.

Das Verbinden mit Kommas ist noch problematischer, wenn dadurch eine gültig aussehende Zeichenkette entsteht. Stell dir einen benutzerdefinierten API-Key-Header vor, bei dem die Anwendung an Kommas teilt, während das Gateway die ganze Zeichenkette vergleicht. Oder einen Bearer-Parser, der den Text nach dem ersten Leerzeichen akzeptiert und Kommas nicht ablehnt. Damit hast du zwei Parser-Sprachen für ein geheimnisbehaftetes Feld geschaffen.

Die verbreitete Empfehlung, «die API einfach entscheiden zu lassen», ist falsch, wenn ein Gateway vor der API Authentifizierung, Ratenbegrenzung, Tenant-Routing oder Audit-Kennzeichnung durchführt. Das Gateway hat bereits eine Sicherheitsentscheidung getroffen. Es muss dieselbe eindeutige Identität wie der Dienst verwenden oder die Anfrage stoppen.

Ein vorhersehbarer Vertrag sieht so aus:

  1. Jeden eingehenden Headernamen normalisieren.
  2. Alle Vorkommen geschützter Felder zählen, bevor Zugangsdaten ausgewählt werden.
  3. Duplikate jedes geschützten Feldes mit einem allgemeinen Clientfehler ablehnen.
  4. Unvereinbare Zugangskanäle ablehnen, wenn die Route nur eine Identitätsquelle akzeptiert.
  5. Geschützte eingehende Felder entfernen, bevor eine vertrauenswürdige Komponente eigene Zugangsdaten für den nächsten Dienst einsetzt.

Führe dies vor dem Parsen von Tokens durch. Wenn das Token-Parsen zuerst läuft, kann ein Parser einen Wert verbrauchen, den die nächste Komponente abgelehnt hätte. Halte die Fehlerantwort nüchtern. Sage dem Aufrufer, dass die Anfrage widersprüchliche Authentifizierungsheader enthält, und gib die Feldwerte nicht aus.

Es gibt seltene APIs, die mehrere Werte eines Feldes absichtlich definieren. Wenn du eine solche API besitzt, dokumentiere Grammatik, Reihenfolge, Verhalten bei Duplikaten und Proxy-Anforderungen als Teil des Authentifizierungsvertrags. «Das Framework kümmert sich darum» ist keine Dokumentation. Wenn du die API nicht besitzt, erfinde keinen Vorrang darum herum.

Benutzerdefinierte Header brauchen einen Zugangsdatenvertrag

Teams behandeln Authorization oft als sensibel und benutzerdefinierte Header als harmlose technische Infrastruktur. Das ist falsch. Ein benutzerdefinierter Header, der einen API-Schlüssel oder Tenant auswählt, ist Authentifizierungsmaterial, unabhängig davon, ob sein Name mit X- beginnt.

Schreibe für jede Route auf, welche Zugangskanäle sie akzeptiert. Eine Route kann ein Bearer-Token aus Authorization akzeptieren. Eine andere kann eine Webhook-Signatur in einem eigenen Header zusammen mit einem Zeitstempel erwarten. Eine interne Route kann einen Identitätsheader nur von einem Gateway erhalten. Das sind getrennte Verträge. Vermeide eine allgemeine Middleware, die einfach die Zugangsdaten verwendet, die sie zuerst findet.

Ein Zugangsdatenvertrag muss diese Fragen beantworten:

  • Darf dieses Feld mehr als einmal vorkommen?
  • Darf es zusammen mit einem anderen Zugangsdatenfeld vorkommen?
  • Welche vertrauenswürdige Komponente darf es hinzufügen?
  • Entfernt ein Proxy das Feld vor der Weiterleitung?
  • Welche Fehlermeldung gibt die API bei einem Konflikt zurück?

Für API-Schlüssel gibt es zwei klare Modelle. Das erste akzeptiert genau ein Authorization-Schema. Das zweite akzeptiert genau einen benannten API-Key-Header. Unterstütze nicht beide auf derselben Route, außer du brauchst dies für eine Migration und hast eine dokumentierte Konfliktregel. Während einer Migration solltest du Anfragen mit beiden Feldern ablehnen und Clients mit einer zeitunabhängigen Migrationsmeldung auf den akzeptierten Ersatz hinweisen. Ein dauerhafter stiller Fallback erzeugt ein dauerhaftes Diagnoseproblem.

Signierte Webhooks brauchen besondere Sorgfalt. Signaturheader können legitime strukturierte Parameter enthalten, und ein Zeitstempel kann die Signatur begleiten. Das bedeutet nicht, dass doppelte Signaturfelder sicher sind. Folge der Dokumentation des Anbieters zur Prüfung und bewahre die erwartete Behandlung des rohen Bodys. Wenn wiederholte Signaturen nicht definiert sind, lehne sie vor der Prüfung ab. Verbinde sie niemals und hoffe, dass die Prüfungsbibliothek die gewünschte Auswahl trifft.

Interne Identitätsheader sind am leichtesten falsch zu behandeln, weil sie bequem sind. Wenn eine Anwendung X-User-Id aus dem öffentlichen Netz akzeptiert und annimmt, ein Proxy habe ihn eingefügt, kann ein Aufrufer jede Identität behaupten. Binde interne Header an einen privaten Netzwerkpfad oder eine authentifizierte Proxy-Verbindung, entferne sie an jedem öffentlichen Edge und stelle sicher, dass nur dein vertrauenswürdiger Proxy den Anwendungsport erreicht. Der Vorrang von Headern kann keine fehlerhafte Netzwerk-Vertrauensgrenze reparieren.

Teste die gesamte Route mit absichtlichen Konflikten

Jeden HTTP-Aufruf eines Agenten sehen
Das Aktivitätsjournal zeichnet einzelne Agentenaufrufe auf, ohne die zugrunde liegenden Zugangsdaten in den Agenten zu übertragen.

Unit-Tests für einen Token-Parser testen keinen Header-Vorrang. Du brauchst einen Integrationstest, der dieselben Komponenten durchläuft wie die Produktion. Das gewünschte Ergebnis ist langweilig und stabil: Jede mehrdeutige Anfrage wird abgelehnt, bevor eine Aktion am nächsten Dienst erfolgt.

Beginne mit einem harmlosen Endpunkt unter deiner Kontrolle. Gib ihm eine Anfragekennung und lasse ihn nur sichere Beobachtungen zurückgeben: normalisierte Headernamen, Anzahlen, Protokollversion und die empfangende Komponente. Gib keine Headerwerte zurück. Setze ihn anschließend hinter dasselbe Edge, Gateway und Dienst-Routing wie die Ziel-API.

Führe eine kleine Konfliktmenge aus:

Authorization zweimal, derselbe Wert
Authorization zweimal, unterschiedliche Werte
Authorization zusammen mit X-API-Key
X-API-Key zweimal, derselbe Wert
Eine vom Aufrufer gelieferte interne Identität zusammen mit der Identität des Gateways

Der Fall mit demselben Wert ist wichtig. Manche Entwickler lehnen nur unterschiedliche Werte ab, weil sie gleiche Werte für harmlos halten. Dadurch entsteht eine Parser-Unterscheidung, die Angreifer testen können, und ein versehentlicher Fehler bleibt unsichtbar. Lehne jedes Duplikat eines geschützten Feldes ab. Ein Aufrufer, der es mit einem Feld erneut versucht, kann sich weiterhin authentifizieren.

Prüfe für jeden Fall zwei Ergebnisse. Erstens erhält der Client eine eindeutige 4xx-Antwort von der Grenze, die für die Regel zuständig ist. Zweitens protokolliert das System am nächsten Dienst keine Aktion unter einer der beiden Identitäten. Eine 401 oder 403 allein beweist nicht, dass die Route sicher war. Ein System am nächsten Dienst kann einen Teil der Anfrage verarbeitet haben, bevor es sie ablehnt.

Wiederhole den Test anschließend mit jeder unterstützten Protokollversion und jedem Pfad. Beziehe die von der Automatisierung verwendeten Clientbibliotheken ein, nicht nur curl. Ein Kommandozeilen-Client, ein Browser-Fetch-Wrapper, eine HTTP-Bibliothek in CI und eine Agentenlaufzeit können Header-Sammlungen unterschiedlich erzeugen. Halte den Test in deiner Bereitstellungssuite, damit ein Proxy- oder Framework-Upgrade eine Ablehnung nicht unbemerkt durch eine Auswahlregel ersetzt.

Wenn ein Vorfall eintritt, erfasse sichere Belege in dieser Reihenfolge. Zeichne den Aufbau der Clientanfrage, die Zugriffsentscheidung am Edge, die ausgehenden Gateway-Header als Namen und Anzahlen sowie die Beobachtung am Eingang der Anwendung auf. Verknüpfe alles mit einer Anfragekennung. Löse einen Vorfall mit doppelten Headern nicht, indem du in der Produktion vollständige Header-Protokollierung aktivierst. So wird ein Authentifizierungsfehler zu einem Verlust von Zugangsdaten.

Gateways müssen ausgehendes Einfügen von Zugangsdaten kontrollieren

Den Tresor in einer App behalten
Nutze die signierte Mac-Menüleisten-App als Zugangsdaten-Grenze, ohne einen separaten Tresordienst.

Ein Aktions-Gateway sollte den Agenten von rohen Zugangsdaten fernhalten und eine Komponente für die endgültige ausgehende Anfrage verantwortlich machen. Wenn du einem Agenten ein Bearer-Token gibst und ihn Header zusammenstellen lässt, erhält er zu viel Berechtigung und zu viele Möglichkeiten, eine fehlerhafte Anfrage zu erzeugen. Außerdem werden Audit-Einträge schwerer verständlich, wenn Standardwerte und benutzerdefinierte Header kollidieren.

Sallyport führt HTTP-Aufrufe mit Zugangsdaten aus seinem verschlüsselten Tresor aus, statt das Geheimnis dem Agenten zu geben. Diese Grenze ist nur dann nützlich, wenn der Builder für ausgehende Anfragen Zugangsdaten-Header als geschützte Felder behandelt und nicht als Vorschläge, die von Agenten-Headern überschrieben werden dürfen.

Für einen geschützten ausgehenden Header sollte das Gateway die gespeicherte Konfiguration auswählen, jede vom Aufrufer gelieferte Instanz dieses Feldes ohne Beachtung der Groß- und Kleinschreibung entfernen und genau einen endgültigen Wert hinzufügen. Für benutzerdefinierte Zugangsdaten-Header gilt dieselbe Regel. Wenn die Zielanfrage einen vom Agenten kontrollierten Header mit demselben Namen benötigt, ist die Konfiguration falsch oder die Ziel-API braucht eine separate Route. Erzeuge keine Ausnahme pro Anfrage, die die Identität unbemerkt verändert.

Dabei ist eine Unterscheidung wichtig. Es ist am vertrauenswürdigen ausgehenden Übergang richtig, einen vom Agenten gelieferten Authorization-Header vor dem Einfügen des konfigurierten Werts zu entfernen. Zwei Header zu akzeptieren und darauf zu hoffen, dass das Ziel sie richtig sortiert, ist falsch. Die erste Aktion schafft eine einzige Quelle für Zugangsdaten. Die zweite exportiert Mehrdeutigkeit.

Ein Gateway muss außerdem konkurrierende Kanäle schützen. Angenommen, eine gespeicherte Verbindung fügt Authorization: Bearer ... ein, während die Agentenanfrage X-API-Key enthält. Das Ziel kann beide akzeptieren. Die sicherste Standardeinstellung ist, die Anfrage wegen widersprüchlicher Zugangsdaten abzulehnen, sofern die Verbindungsdefinition diese Kombination nicht ausdrücklich erlaubt und begründet. Eine allgemeine Header-Allowlist kann das nicht entscheiden, weil die Bedeutung zur Ziel-API gehört.

Audit-Einträge sollten einem Betreiber mitteilen, dass das Gateway eine benannte Verbindung oder Zugangsdatenbezeichnung verwendet hat, welcher Host die Anfrage erhielt, welche Methode und welcher Pfad verwendet wurden und ob eine menschliche Freigabe stattfand. Der Authorization-Wert und geheime benutzerdefinierte Header dürfen nicht gespeichert werden. Das Sallyport-Aktivitätsjournal ist auf einzelne Aufrufe ausgerichtet, aber ein Journal repariert eine mehrdeutige Anfrage nicht nachträglich. Der Builder für die Anfrage muss die Mehrdeutigkeit entfernen, bevor sie das Gerät verlässt.

Protokolle zeigen Vorrangsfehler, ohne Tokens preiszugeben

Fehler mit doppelten Headern bleiben bestehen, weil Teams entweder zu wenig protokollieren, um die Routenänderung zu erkennen, oder zu viel und dadurch einen zweiten Vorfall erzeugen. Du kannst genug aufzeichnen, um das Problem zu diagnostizieren, ohne Zugangsdaten aufzubewahren.

Für jeden abgelehnten Konflikt solltest du eine normalisierte Liste geschützter Headernamen und ihrer Anzahlen erfassen. Ergänze Routennamen, Protokoll, empfangende Komponente, Anfragekennung und einen Grundcode wie duplicate_authorization oder conflicting_credential_channels. Falls es dein Betriebsprozess erlaubt, kannst du eine Kennung der Zugangsdatenkonfiguration erfassen, mit der sich das Geheimnis nicht abrufen lässt.

Protokolliere niemals rohe Bearer-Tokens, API-Schlüssel, Basic-Authentication-Werte, signierte Webhook-Inhalte, Cookies oder vollständige Authorization-Zeilen. Eine nachträgliche Redaction nach der Zeichenkettenformatierung ist unzuverlässig. Eine Bibliothek kann eine Ausnahme mit der ursprünglichen Anfrage auslösen, oder ein Debug-Logger kann vor deinem Redactor laufen. Erzeuge Logeinträge aus sicheren Feldern, statt einen Anfragedump zu nehmen und später zu bereinigen.

Das Hashen eines Tokens ist nicht automatisch sicher. Ein stabiler Hash kann jedem mit Zugriff auf die Protokolle ermöglichen, die Nutzung desselben Zugangsmittels zuzuordnen, und bei Geheimnissen mit geringer Entropie leicht zu erraten sein. Verwende zur Zuordnung eine nicht geheime Zugangsdaten-ID aus deinem Tresor oder deiner Konfiguration. Wenn du keine hast, protokolliere, dass ein unbenannter Zugangskanal vorhanden war, und verbessere das Konfigurationsmodell.

Behandle fehlende Belege als Bereitstellungsfehler. Wenn ein Edge ein Duplikat ablehnt, das Audit-Protokoll aber nicht zeigt, welches Edge diese Entscheidung getroffen hat, werden Einsatzkräfte ihre Zeit mit Anwendungsprotokollen verschwenden, die die Anfrage nie gesehen haben. Wenn dagegen die Anwendung ablehnt, das Edge sie aber durchgelassen hat, hast du eine Stelle gefunden, an der die Durchsetzung verschärft werden muss.

Die erste praktische Korrektur ist klein: Liste die Header mit Zugangsdaten auf einer öffentlichen Route auf, lehne Wiederholungen und Konflikte am Eingang ab und beweise mit einem Integrationstest, dass kein Aufruf am nächsten Dienst erfolgt. Wende denselben Vertrag anschließend auf jeden Proxy-Pfad und jeden ausgehenden Client an. Die Reihenfolge der Header darf niemals entscheiden, wen eine API als Aufrufer betrachtet.

FAQ

Welcher HTTP-Header gewinnt, wenn derselbe Header zweimal vorkommt?

HTTP legt keinen universellen Gewinner für doppelte Feldnamen fest. Ein Empfänger kann manche Felder zusammenführen, die Anfrage ablehnen, den ersten oder letzten Wert behalten oder beide Werte weiterreichen. Für sicherheitsrelevante Felder braucht jede Grenze eine ausdrückliche Regel.

Sollte eine API zwei Authorization-Header akzeptieren?

Behandle doppelte Authorization-Header als Fehler. Wenn du den ersten oder letzten Wert auswählst, hängt die akzeptierte Zugangsdaten von Clientverhalten und Proxy-Umschreibungen ab. Lehne die Anfrage vor der Authentifizierung ab und protokolliere die Duplizierung sicher.

Können unter HTTP/2 doppelte Header entstehen?

Ja, doppelte Header können vorkommen und für erhebliche Verwirrung sorgen. HTTP/2 und HTTP/3 übertragen Header-Felder als strukturierte Headerblöcke, während ein HTTP/1.1-Hop sie anders serialisieren kann. Ein Gateway muss die Regel zur Ablehnung von Duplikaten auch bei der Protokollübersetzung beibehalten.

Führen Reverse-Proxys doppelte HTTP-Header zusammen?

Ein Reverse-Proxy kann beide Felder behalten, sie zusammenfassen, eines entfernen oder eigene Zugangsdaten hinzufügen. Das Ergebnis bestimmen seine Konfiguration und die Reihenfolge der Module, nicht der Browser oder API-Client. Teste den tatsächlich eingesetzten Pfad, statt anzunehmen, der Proxy sei transparent.

Kann ich Authorization und X-API-Key gemeinsam senden?

Verwende einen separaten Header nur, wenn der Dienst dies ausdrücklich dokumentiert, etwa X-API-Key oder einen anbieterspezifischen Zugangsdaten-Header. Sende ihn nicht als Fallback zusammen mit Authorization. Der Server sollte Anfragen mit konkurrierenden Zugangsdaten ablehnen, sofern seine Dokumentation keine sichere und eindeutige Auswahl definiert.

Sind Authorization und authorization unterschiedliche Header?

Nein. HTTP-Headernamen unterscheiden nicht zwischen Groß- und Kleinschreibung. authorization, Authorization und AUTHORIZATION bezeichnen dasselbe Feld. Ein Detektor für Duplikate muss normalisierte Feldnamen vergleichen, nicht deren ursprüngliche Schreibweise.

Kann ich doppelte Authorization-Header mit einem Komma verbinden?

Führe Authorization nicht per Komma zusammen. Kommas können innerhalb der Syntax eines Authentifizierungsschemas vorkommen, und ein Authentifizierungsheader ist normalerweise kein Listenfeld. Lehne die Anfrage ab oder entferne das unerwünschte Feld an einer vertrauenswürdigen Grenze nach einer dokumentierten Regel.

Wie kann ich doppelte Request-Header sicher untersuchen?

Untersuche die rohe Anfrage an jedem Übergang: beim Client, am Edge-Proxy, im Anwendungs-Gateway und in der Anwendung. Protokolliere Headernamen und sichere Metadaten wie Längen oder das Zugangsdaten-Schema, niemals Bearer-Tokens. Ein lokaler Listener hilft zu prüfen, was der Client tatsächlich gesendet hat.

Wird immer der erste Authorization-Header verwendet?

Verlasse dich nicht auf die Reihenfolge. Verschiedene Bibliotheken bewahren wiederholte Felder auf, ordnen sie um, fassen sie zusammen oder überschreiben sie. Auch Vermittler können die Darstellung auf der Leitung ändern. Eine sichere API verhält sich unabhängig von der Reihenfolge gleich und lehnt alle Duplikate ab.

Können auch benutzerdefinierte Authentifizierungsheader doppelt vorkommen?

Gehe nicht davon aus, dass ein benutzerdefinierter Authentifizierungsheader unverändert ankommt. Einige Clients können wiederholte benutzerdefinierte Header senden, andere überschreiben einen Eintrag in einer Map, und Vermittler können eigene Normalisierungen anwenden. Zeichne die Anfrage in einem isolierten Test auf und behalte diesen Test in den Prüfungen vor jeder Veröffentlichung.

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