FastCGI: 30 Years Old and Still the Better Protocol for Reverse Proxies

· security web · Source ↗

TLDR

  • FastCGI’s binary framing and domain-separated parameters eliminate HTTP reverse proxy desync attacks and untrusted-header injection by design.

Key Takeaways

  • HTTP/1.1 desync (request smuggling) stems from ambiguous message framing; FastCGI has had explicit framing since 1996, predating HTTP/2 backend support in nginx (late 2025) and Apache (still experimental).
  • FastCGI prefixes client headers with HTTP_, making it structurally impossible for attackers to spoof trusted proxy parameters like REMOTE_ADDR or TLS metadata.
  • Switching Go apps requires only replacing http.Serve with fcgi.Serve; nginx, Apache, Caddy, and HAProxy all support FastCGI backends with minimal config changes.
  • Known tradeoffs: no WebSocket support, sparse tooling (curl cannot speak FastCGI), and some workloads show worse throughput due to less-optimized code paths.
  • The author has run FastCGI in production at SSLMate for over 10 years despite these limits.

Hacker News Comment Review

  • Commenters surfaced WAS (Web Application Socket) as a further improvement over FastCGI, using a control socket plus raw pipes with splice() to eliminate framing overhead entirely.
  • Debate on the untrusted-header problem: the Forwarded header and HAProxy’s PROXY protocol are partial fixes, but no single standard covers all trusted metadata needs over HTTP.
  • Several commenters noted they were already using FastCGI unknowingly via PHP-FPM or Apache configs, underscoring how invisible the protocol is in common stacks.

Notable Comments

  • @max_k: Designed WAS 16 years ago; uses raw pipes so both sides can call splice(), removing framing cost FastCGI still carries.
  • @nostrademons: HTTP won the proxy-protocol wars via simplicity and topology flexibility, not security superiority – an omission the article glosses over.

Original | Discuss on HN