2 puan yazan GN⁺ 2026-04-30 | 2 yorum | WhatsApp'ta paylaş
  • Uzun süre çalışan backend'lere istekleri soket üzerinden ileten bir proxy protokolü olarak, mevcut HTTP handler yapısını neredeyse hiç değiştirmeden uygulanabilir
  • HTTP/1.1 ters proxy kullanımında mesaj sınırlarının yorumlanması implementasyondan implementasyona kaymaya yatkındır; bu da desync ve request smuggling gibi ciddi güvenlik sorunlarını sürekli üretebilir
  • FastCGI, 1996'dan beri açık mesaj çerçevelemesi sunuyor ve istemci başlıklarıyla proxy'nin eklediği güvenilir bilgileri yapısal olarak ayırıyor
  • Go'nun net/http/fcgi paketi REMOTE_ADDR değerini Request.RemoteAddr alanına doldurur ve HTTPS durumunu da Request.TLS içine yansıtır; böylece güvenilir bilgi aktarımı ek middleware olmadan sağlanabilir
  • WebSockets desteğinin olmaması, zayıf araç ekosistemi ve bazı iş yüklerinde düşük throughput gibi sınırlamalar var; ancak WebSockets gerekmiyor ve performans yeterliyse hâlâ pratik bir seçenek gibi görünüyor

FastCGI'nin konumu ve uygulanma biçimi

  • FastCGI, yalnızca dosya başına süreç çalıştırma modelinde değil, uzun süre çalışan daemon'lara TCP veya UNIX soketi üzerinden istek gönderen bir proxy-backend protokolü olarak da kullanılabilir
  • Go'da net/http/fcgi paketini içe aktarıp http.Serve çağrısını fcgi.Serve ile değiştirmek kadar basit olabilir
    • Mevcut handler'lar olduğu gibi http.ResponseWriter ve http.Request kullanmaya devam eder
    • Uygulamanın geri kalan yapısı da korunur
  • Apache, Caddy, nginx, HAProxy gibi başlıca proxy'ler FastCGI backend'lerini destekler ve yapılandırmaları da görece basittir

HTTP'nin backend protokolü olarak kullanılmasındaki ayrıştırma sorunları

  • HTTP reverse proxying, neredeyse bir güvenlik mayın tarlasıdır; Discord medya proxy'sindeki desync zafiyeti gibi özel ekleri gözetlemeye yol açabilen sorunlar çıkmaya devam ediyor
  • HTTP/1.1 görünüşte basit bir metin protokolüdür, ancak aynı mesajı ifade etmenin aşırı fazla yolu ve çok sayıda istisna durumu olduğundan implementasyonlar arasında yorum farkı oluşması kolaydır
  • En büyük sorun, HTTP mesajlarında açık çerçeveleme bulunmamasıdır
    • Mesajın sonunu, mesajın kendisi birden fazla yolla tarif eder
    • Farklı implementasyonlar bir mesajın bittiği ve sonraki mesajın başladığı noktayı farklı yorumlayabilir
  • Bu tür uyumsuzluklar, HTTP desync attacks veya request smuggling saldırılarının temelini oluşturur; ters proxy ile backend mesaj sınırlarını farklı anladığında ciddi güvenlik sorunları ortaya çıkar
  • Parser farklarını sürekli yamalamak kökten bir çözüm olmaya pek uygun değildir
    Reklam

FastCGI ve HTTP/2'de mesaj sınırı işleme

  • HTTP/2, proxy ile backend arasında tutarlı biçimde kullanıldığında mesaj sınırlarını netleştirerek desync sorununu çözebilir
  • FastCGI ise bu net sınır ayrımını 1996'dan beri daha basit bir protokolle sunuyor
  • nginx, ilk sürümünden beri FastCGI backend desteğine sahipti; buna karşın HTTP/2 backend desteği ancak 2025'in sonlarına doğru eklendi
  • Apache'nin HTTP/2 backend desteği ise hâlâ "experimental" durumunda

Güvenilmeyen başlıklar sorunu ve FastCGI'nin ayırma yöntemi

  • Sorun sadece desync değildir; HTTP ayrıca gerçek istemci IP'si, proxy'nin işlediği doğrulanmış kullanıcı adı ya da mTLS'teki istemci sertifikası bilgisi gibi proxy'nin güvenerek iletmesi gereken verileri sağlam biçimde taşımakta da yetersiz kalır
  • Pratikte bu bilgiler HTTP başlıklarına konur, ancak proxy'nin eklediği güvenilir veriler ile istemcinin gönderdiği güvenilmeyen başlıklar arasında yapısal bir ayrım yoktur
  • X-Real-IP gibi başlıklar gerçek istemci IP'sini iletmek için sık kullanılır, ancak güvenli olması için proxy'nin büyük/küçük harf varyasyonları dâhil tüm mevcut başlıkları tamamen silip sonra yeniden eklemesi gerekir
  • Bu yaklaşım çok tehlikeli bir zemindir ve backend'in saldırganın yerleştirdiği verilere güvenmesine yol açan birçok yol vardır
  • Proxy, yalnızca X-Real-IP değil, bu amaçla kullanılan her türlü başlığı silmek zorundadır
  • Örneğin Chi middleware'i, istemcinin gerçek IP'sini belirlerken önce True-Client-IP başlığını kontrol eder; yalnızca o yoksa X-Real-IP kullanır
    • Proxy X-Real-IP'yi doğru işlese bile saldırgan True-Client-IP gönderirse sorun çıkabilir
  • FastCGI, istemci başlıkları ile proxy'nin eklediği bilgileri alan ayrımı yoluyla ayırır
    • Her ikisi de anahtar/değer parametre listesi olarak taşınır, ancak HTTP başlık adlarında HTTP_ öneki bulunur
    • Böylece istemcinin gönderdiği bir başlığın proxy'nin güvenilir verisi gibi yorumlanacağı bir yapı ortaya çıkmaz

Go'da FastCGI ile güvenilir bilgi işleme

  • FastCGI, gerçek istemci IP'sini iletmek için REMOTE_ADDR gibi standart parametreler tanımlar
  • Go'nun net/http/fcgi paketi bu değeri otomatik olarak http.Request içindeki RemoteAddr alanına yerleştirir; dolayısıyla ek middleware gerekmez
  • Proxy, HTTPS kullanımı, uzlaşılan TLS cipher suite ya da istemci sertifikası gibi bilgileri standart dışı parametrelerle de iletebilir
  • Go, istek HTTPS kullandığında Request içindeki TLS alanını otomatik olarak nil olmayan bir değere ayarlar
    • Boş olsa bile HTTPS zorunluluğunu denetlemek için faydalıdır
    Reklam
  • fcgi.ProcessEnv ile proxy'nin gönderdiği güvenilir parametrelerin tamamına erişilebilir

Yaygınlaşmasının yavaş olmasının nedenleri ve pratik sınırlamalar

  • FastCGI daha iyiyse neden yaygın kullanılmadığı sorusuna, isminin bile eski hissettirmesi ve HTTP reverse proxy güvenlik sorunlarına dair farkındalığın az olması birlikte etki etmiş gibi görünüyor
  • Watchfire, 2005'te desync saldırılarını zaten ele almış ve çözümün kolay olmadığı uyarısını yapmıştı; ancak bu saldırılar 10 yıldan uzun süre boyunca hak ettiği ilgiyi görmedi
  • FastCGI bugün de gerçek kullanım için uygundur; SSLMate bunu 10 yıldan uzun süredir production ortamında kullanıyor
  • Yine de eski bir teknoloji olduğu için zayıf yönleri var
    • WebSockets desteği için güncellenmedi
    • Araç ekosistemi yetersiz
    • Örneğin curl, FTP, Gopher ve SMTP'yi bile destekliyor ama FastCGI isteği gönderemiyor
  • Go FastCGI sunucusu birden çok reverse proxy arkasında benchmark edildiğinde, bazı iş yüklerinde HTTP/1.1 veya HTTP/2'den daha düşük throughput görüldü
    • Bunun protokolün doğasından çok, FastCGI kod yolunun HTTP kadar optimize edilmemiş olmasının sonucu olduğu düşünülüyor

Nihai değerlendirme

  • WebSockets gerekmiyorsa ve mevcut performans yeterliyse FastCGI hâlâ değerlendirilebilir bir seçenektir
  • Darboğaz oluşsa bile, HTTP reverse proxying'in karmaşıklığını ve güvenlik kâbusunu üstlenmektense ek donanım kullanmayı tercih etmek daha mantıklı görünüyor

2 yorum

 
rtyu1120 2026-04-30

Lobsters yorumlarında bulduğum, Twisted’in FastCGI hakkındaki yorumu etkileyici görünüyor: https://web.archive.org/web/20160723091923/…

 
GN⁺ 2026-04-30
Hacker News görüşleri
  • Yazının ana fikrine katılıyorum. Bu tür bir kullanım için FastCGI'nin HTTP'den daha iyi olduğunu düşünüyorum
    WAS (Web Application Socket) adlı bir protokolden de bahsetmek isterim. 16 yıl önce iş yerimde FastCGI'nin bile yeterince iyi olmadığını düşünüp bunu bizzat tasarladım
    Ana soket framing'i yerine bir kontrol soketi ve ham istek/yanıt gövdeleri için iki pipe kullanıyor; hem WAS uygulaması hem de web sunucusu pipe'larda splice() kullanabiliyor
    Framing gerekmiyor, istek iptali mümkün ve üç dosya tanımlayıcısının her zaman kurtarılabilmesini sağladım
    Bunu yıllardır dahili uygulamalarda ve web hosting ortamlarında kullanıyoruz; PHP SAPI'sini de kendim yazdım. Epey çok web sitesi dahili olarak WAS üzerinde çalışıyor
    Hepsi açık kaynak
    library: https://github.com/CM4all/libwas
    documentation: https://libwas.readthedocs.io/en/latest/
    non-blocking library: https://github.com/CM4all/libcommon/tree/master/src/was/asyn...
    our web server: https://github.com/CM4all/beng-proxy
    WebDAV: https://github.com/CM4all/davos
    PHP fork with WAS SAPI: https://github.com/CM4all/php-src

    • FastCGI ile HTTP aynı katmanda değil
      HTTP, tarayıcı ile sunucu gibi iki uç arasında veri taşımak içindir; FastCGI ise bu veriyi sunucu ile uygulama arasında işlemek içindir
      Yazıya az önce göz attım; yazar sanki ikisi birbirinin yerine geçebilirmiş gibi kafa karıştırıcı bir dil kullanıyor. Oysa gerçekte hiç öyle değil
      Bu arada ben de web müşteri hizmetlerinde fcgi'yi 10 yıldır kullanıyorum
  • Bu yazı, eksik bıraktıkları yüzünden daha da ilginç
    FastCGI vs. SCGI vs. HTTP tartışmalarının hararetli olduğu dönemde bir Web2.0 girişimi kurup frontend stack'i kendim oluşturmuştum; sonunda HTTP'nin kazanma sebebi basitlik oldu
    Gateway'de zaten işlenmesi gereken HTTP'yi olduğu gibi kullanınca stack'e başka bir protokol eklemeye gerek kalmıyordu; bu da reverse proxy'yi birden fazla katman halinde yerleştirmeyi ya da kimlik doğrulama, oturum, SSL termination, DDoS filtreleme gibi çapraz sorumlulukları role göre ayrılmış sunuculara bölmeyi çok kolaylaştırıyordu
    Geliştirme ortamında uygulama sunucusuna HTTP ile doğrudan bağlanabiliyor, üretimdeyse SSL, kimlik doğrulama ve kötüye kullanım tespitini reverse proxy'ye bırakırken aynı uygulama sunucusunu aynen yeniden kullanabiliyorduk
    O dönemde nginx'in çoğu FastCGI/SCGI modülünden çok daha hızlı ve kararlı olması da önemliydi. Başta HTTP -> Lighttpd -> FastCGI -> Django yapısı kullanmıştık ama doğrudan nginx kullanmak çok daha hızlıydı
    HTTP kullanımı, web sürümünde bir End-to-End Principle gibi işliyordu. Ağın ve protokolün taşınan içeriğe kayıtsız olması, uygulama mantığının da filtreleyen ya da yönlendiren ağ düğümlerinde değil uç noktalarda bulunması gerektiği fikri
    Ama yazının asıl işaret ettiği nokta şu: güvenlik açısından çoğu zaman en az ayrıcalık ilkesine uymak daha iyi oluyor. Yalnızca beklenen iletişimi allowlist ile geçirmek gerekir ki başka bir noktadaki ihlale farkında olmadan katkı sağlanmasın
    Sonuçta bu ikisi arasında bir gerilim var. E2E esneklik sağlar ama bu esneklik suistimal ihtimalini de artırır; PoLP güvenlik sağlar ama yalnızca tasarladığınız şeyleri yapabildiğiniz için yeni gereksinimlere uyum zorlaşır
    [1] https://en.wikipedia.org/wiki/End-to-end_principle
    [2] https://en.wikipedia.org/wiki/Principle_of_least_privilege

    • O benzetmenin pek uygun olduğunu düşünmüyorum. Özellikle connection caching ve multiplexing bağlamında daha da değil
      Eğer ara gateway birçok HTTP isteğini başka bir HTTP kanalı üzerinde multiplex ediyor, o kanal listening service'e doğrudan gidiyor ve uygulama soketine gelmeden önce demultiplex edilmiyorsa, bu end-to-end mantığını çeşitli şekillerde temelden bozar
      Bu benzetme ancak 1:1 bağlantı simetrisi korunduğunda bir ölçüde anlamlı olabilir
      Reverse proxy açıklarının tamamının end-to-end'in ihlal edilmesinden doğrudan kaynaklandığını düşünüyorum
      Eğer benzetme doğru olsaydı, birden fazla MX üzerinden yapılan SMTP iletimi de end-to-end sayılmalıydı; ama öyle değil ve reverse proxy'lerdeki sorunlara benzer şekilde, örneğin mesaj sınırı desync'i gibi pek çok problem de ortaya çıkıyor
      HTTP isteğini mesaja eşlemeye yönelik niyeti anlıyorum ama gerçek TCP/HTTP semantiği ve sayısız protokol ayrıntısı yüzünden bu yaklaşım hemen çöküyor
      End-to-end ilkesi semantiğin kabaca ele alınmasına izin vermez. Durum yönetimi ve taşıma katmanı sınırları konusunda çok sıkı bir disiplin ister. Kabaca end-to-end'e benzeyen bir şey, end-to-end değildir
    • Web uygulaması geliştiricileri için HTTP semantics faydalı ama HTTP wire protocol'ünün kendisi berbat
      Örneğin multiplexing, HTTP 2.0'a kadar yoktu; bu yüzden reverse proxy ile backend arasında HTTP'yi aynen kullanmak ciddi israf
      Güvenlik sorunları da var. Parser'lar istek sınırının tam olarak nerede bittiğini birbirinden farklı yorumlayabiliyor
      Google da uzun zamandır frontend web sunucusu ile uygulama arasında HTTP'yi kendi Stubby protokolüyle sarmalayarak kullanıyor
      HTTP wire protocol'ünden çok daha hızlı ve daha çok özellik sunuyor. Çoğu şirket için fazla olur ama ölçek büyüdüğünde başka bir wire protocol ve etrafındaki araçları kendin geliştirmenin maliyeti rahatlıkla karşılığını veriyor
    • Veri merkezi içinde end-to-end principle uygulamanın pek anlamı yok; yazının da gösterdiği gibi bu, tersine güvensiz davranışlara izin verebiliyor
    • nginx'te sevmediğim şey dokümantasyon. Dürüst olmak gerekirse neredeyse hiç işe yaramıyor gibi geliyor
      httpd de bir noktada yapılandırmayı gereksiz zorlaştıran bir yöne gitti ve yapılandırma formatını bir anda değiştirdiğinde onu bıraktım
      Elbette alışabilirdim ama onun yerine lighttpd'ye geçtim; sonrasında ruby yapılandırma üretimini otomatikleştirdiği için teknik olarak yeniden httpd'ye dönebilirdim
      Yine de dönmek istemem. Web sunucusu geliştiricileri, kullanıcılarını yeni bir formata zorla uydurma konusuna dikkatli yaklaşmalı
      Yapılandırma formatını gerçekten bu kadar kolay değiştirecekseniz, en azından ek seçenek olarak yaml yapılandırması gibi bir şey sunun da insanları aniden yeni bir if-clause tarzı yapılandırma sözdizimine mecbur bırakmayın
  • WHATWG streams artık tarayıcılarda yaygın olduğuna göre, uzun ömürlü HTTP istekleri üzerinde WebSocket benzeri kendi çözümünüzü kurmak epey kolay
    Sadece bir byte stream gönderip her mesajın önüne bir başlık koyuyorsunuz; çoğu durumda tek bir uzunluk değeri bile yeterli
    Avantajları da var. WebSocket'teki gibi sunucu katmanında ayrı özel bir yol gerekmiyor, backpressure kullanılabiliyor, HTTP/2 ve HTTP/3 iyileştirmeleri bedavaya geliyor ve framing overhead'i daha düşük oluyor
    Ancak AFAIK, istek gövdesini sürekli stream ederken aynı anda yanıt almak hâlâ desteklenmiyor; bu yüzden tam çift yönlü streaming için iki istek gerekiyor

  • Eski plain CGI'yi yeniden keşfettim; platformumuzda kullanıcıların özel sayfaları vibe code etmesini sağlamak için harika [1]
    Yerleşik özellikler olarak görev listesi ve veri görüntüleyici sunuyoruz ama kullanıcılar sık sık Kanban görünümü veya veri filtreleri ve grafikler içeren özel dashboard'lar gibi çok daha ince ayarlı özelleştirmeler istiyor
    Bu kutuda bir coding agent var; bu sayede bizim klasik bir report builder yapmamız yerine kullanıcı istediğini doğrudan kodlayabiliyor
    Go stdlib hem sunucu tarafında hem kullanıcı alanında iyi destek veriyor; coding agent page-name/main.go oluşturup CGI üzerinden konuşturulunca sunucu isteği oraya devrediyor
    Veri boyutu da sayfa görüntüleme sayısı da tamamen person scale, dolayısıyla FastCGI gibi optimizasyonlara pek ihtiyaç olmuyor
    Ajan çağında eski teknoloji yeniden yeni oluyor

    1. https://housecat.com
    • CGI'nin FastCGI'den farklı olarak HTTP başlıklarını ortam değişkenleri üzerinden ilettiğini ve bunun epey büyük bir tuzak olduğunu unutmamak gerek: https://httpoxy.org/
      Go'nun CGI sunucu uygulaması $HTTP_PROXY ayarlamadığı için bu açıdan güvenli, ama yine de CGI'nin ortam değişkenleri kullanma biçimini sevmiyorum
  • Reverse proxy tarafı genelde basit işler yaptığı için Nginx'in yerleşik özellikleri çoğu zaman yeterli oluyordu
    Yine de daha karmaşık bir şey gerektiğinde FastCGI kullanma fikri benim aklıma herhalde gelmezdi
    Yaklaşık 10 yıl önce bazı C++ kodlarını web üzerinden çalıştırmak için biraz FastCGI kullandım ama ondan sonra neredeyse hiç kullanmadım

    • Bugünlerde embedded server çok daha yaygın
      Uygulamanın içine doğrudan bir HTTP sunucusu gömüp, gateway olmadan gereken işi orada hallediyorsunuz
  • Red Hat tabanlı dağıtımlarda gelen PHP/Apache yapılandırması FPM (FastCGI Process Manager)
    RHEL dağıtımlarında FastCGI'nin başka nerelerde kullanıldığını bilmiyorum
    $ rpm -qi php-fpm | grep ^Summary
    Summary : PHP FastCGI Process Manager

  • uwsgi protocol diye bir şey de var
    Bu da esasen neredeyse her şey için bir tür RPC gibi

  • FCGI aynı zamanda bir orkestrasyon sistemi
    Yük artınca daha fazla sunucu görevi başlatıyor, yük azalınca kapatıyor ve görev ölürse yeni bir kopya başlatıyor
    Bir bakıma tek sistemlik Kubernetes gibi

    • Benim deneyimimde o özellik pek iyi değildi
      Kulağa hoş geliyor ama normalde düşük yükte iyi çalışırken yüksek yük geldiğinde daha fazla worker üretip belleği tüketmesi sık görülen bir şeydi
      Bu yüzden sabit worker sayısı kullanmak genelde daha iyi sonuç veriyordu
      Yine de gerekiyorsa crash recovery faydalı olabilir
    • Biz de tam olarak bu şekilde kullandık
  • HTTP başlıklarının saçmalığı üzerine kısa bir an düşünelim
    True-Client-IP yoksa X-Real-IP kullanıyorsanız, proxy X-Real-IP'yi doğru biçimde eklese bile saldırgan True-Client-IP başlığı göndererek sizi kandırabilir
    X-Forwarded-For, X-Real-IP, her CDN'in kendi kafasına göre koyduğu özel başlıklar var; bazıları virgülle ayrılmış listeler ve çoğu zaman bizim own LB'nin IP'si de gereksiz yere sonuna eklenmiş oluyor
    Neden böyle olduğunu anlıyorum ama bu hiç yardımcı olmuyor
    Üstelik bu başlıkların hepsi kötü niyetli bir user-agent tarafından da enjekte edilebilir. Sanki güvenilen sunucuların boru hattı içinde kritik bilgiyi nasıl iletmesi gerektiği konusunda kimse uzlaşamamış gibi
    Bu karmaşa, User-Agent başlığının saçmalığıyla da iyi uyum sağlıyor
    Orada da Apple, gizlilik bahanesiyle tamamen sahte bilgiler, örneğin yanlış OS sürümü gibi saçmalıklar göndermeyi seçerek işi daha da uç noktaya taşıdı

  • Bu iddiada çok haklı yanlar var ama FastCGI, PATH_INFO gibi kısımlarda CGI/1.1'i takip ettiği için bilgi kaybına yol açıyor
    URL decoding zorunlu olduğundan encoded slash %2F ifade edilemiyor
    Uygulamaya göre yoldaki // de / olarak birleştirilebiliyor; gerçi bu pek çok HTTP uygulamasında da görülen bir sorun
    İfade gücü açısından HTTP'den daha zayıf ve bunun önemli olup olmadığı uygulamaya bağlı
    Ben URL'lerin tam ve doğru biçimde ele alınmasını tercih ediyorum