1 Punkte von GN⁺ 1 시간 전 | Noch keine Kommentare. | Auf WhatsApp teilen
  • Als Proxy-Protokoll, das Anfragen per Socket an lang laufende Backends weiterreicht, lässt es sich einsetzen, ohne die bestehende HTTP-Handler-Struktur groß zu verändern
  • HTTP/1.1-Reverse-Proxying neigt dazu, dass die Interpretation von Nachrichtenbegrenzungen je nach Implementierung auseinanderläuft, was weiterhin schwerwiegende Sicherheitsprobleme wie Desync und Request Smuggling verursachen kann
  • FastCGI bietet seit 1996 ein klares Message Framing und trennt strukturell Client-Header von Vertrauensinformationen, die der Proxy hinzugefügt hat
  • Gos net/http/fcgi füllt REMOTE_ADDR in Request.RemoteAddr ein und spiegelt auch den HTTPS-Status in Request.TLS wider, sodass die Weitergabe von Vertrauensinformationen ohne zusätzliches Middleware-Setup funktioniert
  • Es gibt Einschränkungen wie fehlende WebSockets-Unterstützung, ein schwaches Tooling-Ökosystem und geringeren Durchsatz bei manchen Workloads, aber wenn keine WebSockets benötigt werden und die Leistung ausreicht, bleibt es eine praktikable Wahl

Die Rolle von FastCGI und wie es eingesetzt wird

  • FastCGI wird nicht nur für das pro Datei ausgeführte Prozessmodell verwendet, sondern kann auch als Proxy-Backend-Protokoll dienen, bei dem Anfragen per TCP- oder UNIX-Socket an einen lang laufenden Daemon gesendet werden
  • In Go reicht es, das Paket net/http/fcgi zu importieren und http.Serve durch fcgi.Serve zu ersetzen
    • Bestehende Handler verwenden weiterhin http.ResponseWriter und http.Request
    • Auch die übrige Struktur der Anwendung bleibt unverändert
  • Wichtige Proxys wie Apache, Caddy, nginx und HAProxy unterstützen FastCGI-Backends, und die Konfiguration ist vergleichsweise einfach

Parsing-Probleme bei HTTP als Backend-Protokoll

  • HTTP-Reverse-Proxying kommt einem sicherheitstechnischen Minenfeld nahe, und es tauchen weiterhin Probleme auf, die wie die Desync-Schwachstelle im Discord-Media-Proxy private Anhänge ausspähen können
  • HTTP/1.1 wirkt auf den ersten Blick wie ein einfaches textbasiertes Protokoll, bietet aber zu viele Möglichkeiten, dieselbe Nachricht darzustellen, und enthält viele Sonderfälle, sodass Implementierungen sie leicht unterschiedlich interpretieren
  • Das größte Problem ist, dass HTTP-Nachrichten keine explizite Framing-Definition haben
    • Das Ende einer Nachricht wird innerhalb der Nachricht selbst auf mehrere Arten beschrieben
    • Je nach Implementierung kann unterschiedlich interpretiert werden, wo eine Nachricht endet und die nächste beginnt
  • Solche Abweichungen bilden die Grundlage für HTTP-Desync-Angriffe beziehungsweise Request Smuggling und führen zu schweren Sicherheitsproblemen, wenn Reverse Proxy und Backend Nachrichtenbegrenzungen unterschiedlich verstehen
  • Parser-Unterschiede immer weiter zu patchen, dürfte keine grundlegende Lösung sein
    • James Kettle entdeckt weiterhin neue Varianten
    • Nachdem er im vergangenen Jahr weitere Fälle gefunden hatte, verwendete er sogar die Formulierung "HTTP/1.1 must die"

Behandlung von Nachrichtenbegrenzungen in FastCGI und HTTP/2

  • HTTP/2 kann Desync-Probleme lösen, wenn es zwischen Proxy und Backend konsistent verwendet wird, weil es Nachrichtenbegrenzungen klar definiert
  • FastCGI bietet diese klare Trennung seit 1996 bereits mit einem einfacheren Protokoll
  • nginx unterstützt FastCGI-Backends seit der ersten Veröffentlichung, aber HTTP/2-Backends wurden erst Ende 2025 hinzugefügt
  • Die Unterstützung für HTTP/2-Backends in Apache befindet sich weiterhin im Status "experimental"

Das Problem unvertrauenswürdiger Header und FastCGIs Trennungsansatz

  • Nicht nur bei Desync, auch für Daten, die ein Proxy vertrauenswürdig weiterreichen muss — etwa die tatsächliche Client-IP, den vom Proxy behandelten authentifizierten Benutzernamen oder Informationen zum Client-Zertifikat bei mTLS — fehlt HTTP ein robuster Transportmechanismus
  • In der Praxis werden diese Informationen daher in HTTP-Header geschrieben, aber zwischen Vertrauensdaten, die der Proxy hinzugefügt hat, und unvertrauenswürdigen Headern vom Client gibt es keine strukturelle Trennung
  • Header wie X-Real-IP werden häufig verwendet, um die echte Client-IP weiterzugeben, aber sicher ist das nur, wenn der Proxy zuvor alle vorhandenen Varianten dieses Headers einschließlich Groß-/Kleinschreibungsvarianten vollständig entfernt und ihn dann neu setzt
  • Dieser Ansatz ist extrem riskantes Terrain, und es gibt viele Wege, auf denen das Backend am Ende doch Daten vertraut, die ein Angreifer eingeschleust hat
  • Der Proxy muss nicht nur X-Real-IP, sondern jeden Header für solche Zwecke vollständig löschen
  • Zum Beispiel prüft Chi-Middleware bei der Bestimmung der tatsächlichen Client-IP zuerst True-Client-IP und verwendet X-Real-IP nur, wenn dieser fehlt
    • Selbst wenn der Proxy X-Real-IP korrekt verarbeitet, kann ein Angreifer Probleme verursachen, indem er True-Client-IP mitsendet
  • FastCGI trennt Client-Header und vom Proxy hinzugefügte Informationen über eine Art Domain Separation
    • Beides wird zwar als Liste von Schlüssel/Wert-Parametern übertragen, aber HTTP-Headernamen erhalten das Präfix HTTP_
    • Dadurch kann ein vom Client gesendeter Header strukturell nicht als Vertrauensdatum des Proxys interpretiert werden

Umgang mit Vertrauensinformationen in Go über FastCGI

  • FastCGI definiert Standardparameter wie REMOTE_ADDR, um die tatsächliche Client-IP zu übermitteln
  • Gos net/http/fcgi übernimmt diesen Wert automatisch in http.Request.RemoteAddr, sodass es ohne zusätzliche Middleware funktioniert
  • Der Proxy kann auch Informationen wie die Nutzung von HTTPS, die ausgehandelte TLS Cipher Suite oder das Client-Zertifikat über nicht standardisierte Parameter weitergeben
  • Go setzt das TLS-Feld von Request automatisch auf einen nicht-nil-Wert, wenn die Anfrage HTTPS verwendet hat
    • Das ist selbst dann nützlich, wenn es leer ist, um zu prüfen, ob HTTPS erzwungen wurde
  • Über fcgi.ProcessEnv lässt sich auf den vollständigen Satz vertrauenswürdiger Parameter zugreifen, die der Proxy übermittelt hat

Warum die Verbreitung schleppend ist und welche praktischen Grenzen es gibt

  • Wenn FastCGI besser ist, warum wird es dann nicht breit genutzt? Dazu tragen offenbar sowohl der veraltete Klang des Namens als auch ein mangelndes Bewusstsein für die Sicherheitsprobleme von HTTP-Reverse-Proxying bei
  • Watchfire behandelte Desync-Angriffe bereits 2005 und warnte auch davor, dass sie sich nicht leicht beheben lassen, aber solche Angriffe bekamen über mehr als zehn Jahre hinweg kaum echte Aufmerksamkeit
  • FastCGI ist auch heute noch praxistauglich, und bei SSLMate wird es seit über zehn Jahren in Produktion eingesetzt
  • Allerdings hat diese alte Technologie auch Schwächen
    • Sie wurde nicht für WebSockets-Unterstützung weiterentwickelt
    • Das Tooling-Ökosystem ist schwach
    • Zum Beispiel unterstützt curl sogar FTP, Gopher und SMTP, kann aber keine FastCGI-Anfragen senden
  • Beim Benchmarking eines Go-FastCGI-Servers hinter mehreren Reverse Proxys zeigten einige Workloads weniger Durchsatz als HTTP/1.1 oder HTTP/2
    • Das wird eher als Folge davon gesehen, dass der FastCGI-Codepfad nicht so stark optimiert ist wie HTTP, und nicht als grundsätzliche Grenze des Protokolls

Schlussurteil

  • Wenn keine WebSockets benötigt werden und die aktuelle Leistung ausreicht, ist FastCGI weiterhin eine brauchbare Option
  • Selbst wenn ein Flaschenhals entsteht, erscheint es sinnvoller, zusätzliche Hardware einzusetzen, als die Komplexität und den Sicherheitsalbtraum von HTTP-Reverse-Proxying in Kauf zu nehmen

Noch keine Kommentare.

Noch keine Kommentare.