2 poin oleh GN⁺ 2026-04-30 | 2 komentar | Bagikan ke WhatsApp
  • Sebagai protokol proxy untuk meneruskan permintaan lewat soket ke backend yang berjalan jangka panjang, ini dapat diterapkan hampir tanpa mengubah struktur handler HTTP yang ada
  • Reverse proxy HTTP/1.1 mudah mengalami perbedaan interpretasi batas pesan antar implementasi, sehingga terus memunculkan masalah keamanan serius seperti desync dan request smuggling
  • FastCGI telah menyediakan framing pesan yang jelas sejak 1996, serta memisahkan secara struktural header klien dan informasi tepercaya yang ditambahkan proxy
  • net/http/fcgi di Go mengisi REMOTE_ADDR ke Request.RemoteAddr dan juga mencerminkan status HTTPS ke Request.TLS, sehingga penyampaian informasi tepercaya bisa ditangani tanpa middleware terpisah
  • Meski ada keterbatasan seperti tidak mendukung WebSockets, ekosistem alat yang lemah, dan throughput lebih rendah pada sebagian workload, ini tetap tampak sebagai pilihan praktis jika WebSockets tidak dibutuhkan dan performanya sudah memadai

Posisi dan cara penerapan FastCGI

  • FastCGI bukan hanya dipakai untuk model eksekusi proses per file, tetapi juga bisa digunakan sebagai protokol proxy-backend yang mengirim permintaan ke daemon yang berjalan terus-menerus melalui soket TCP atau UNIX
  • Di Go, penerapannya cukup dengan mengimpor paket net/http/fcgi dan mengganti http.Serve menjadi fcgi.Serve
    • Handler yang ada tetap menggunakan http.ResponseWriter dan http.Request
    • Struktur aplikasi lainnya juga tetap dipertahankan
  • Proxy utama seperti Apache, Caddy, nginx, dan HAProxy mendukung backend FastCGI, dan konfigurasinya juga relatif sederhana

Masalah parsing saat memakai HTTP sebagai protokol backend

  • Reverse proxy HTTP nyaris seperti ladang ranjau keamanan, dan masalah seperti kerentanan desync pada media proxy Discord yang memungkinkan mengintip lampiran privat terus bermunculan
  • HTTP/1.1 tampak seperti protokol teks yang sederhana, tetapi memiliki terlalu banyak cara untuk mengekspresikan pesan yang sama dan banyak penanganan pengecualian, sehingga tiap implementasi mudah menafsirkannya secara berbeda
  • Masalah terbesarnya adalah HTTP tidak memiliki framing eksplisit untuk pesan
    • Akhir pesan dijelaskan oleh pesan itu sendiri dengan berbagai cara
    • Tiap implementasi bisa menafsirkan titik akhir pesan dan awal pesan berikutnya secara berbeda
  • Ketidaksesuaian seperti ini menjadi dasar HTTP desync attacks atau request smuggling, ketika reverse proxy dan backend memahami batas pesan secara berbeda lalu memicu masalah keamanan serius
  • Menambal terus-menerus perbedaan parser sulit menjadi solusi mendasar

Penanganan batas pesan di FastCGI dan HTTP/2

  • HTTP/2 dapat menyelesaikan masalah desync dengan memperjelas batas pesan jika digunakan secara konsisten antara proxy dan backend
  • FastCGI telah menyediakan pemisahan batas yang jelas ini sejak 1996 dengan protokol yang lebih sederhana
  • nginx mendukung backend FastCGI sejak rilis pertamanya, tetapi dukungan backend HTTP/2 baru ditambahkan pada paruh akhir 2025
  • Dukungan backend HTTP/2 di Apache masih berstatus "experimental"

Masalah header tak tepercaya dan cara pemisahan di FastCGI

  • Bukan hanya soal desync, HTTP juga kurang memiliki cara yang kuat untuk membawa data yang harus dipercaya dan diteruskan proxy, seperti IP klien sebenarnya, nama pengguna hasil autentikasi oleh proxy, atau informasi sertifikat klien pada mTLS
  • Dalam praktiknya, informasi seperti ini dimasukkan ke header HTTP, tetapi tidak ada pemisahan struktural antara data tepercaya yang ditambahkan proxy dan header tak tepercaya yang dikirim klien
  • Header seperti X-Real-IP sering dipakai untuk meneruskan IP klien sebenarnya, tetapi agar aman proxy harus menghapus sepenuhnya semua header yang sudah ada lalu menambahkannya kembali, termasuk variasi huruf besar-kecil
  • Pendekatan ini adalah medan yang sangat berbahaya, dan ada banyak jalur yang membuat backend mempercayai data yang dimasukkan penyerang
  • Proxy harus menghapus bukan hanya X-Real-IP, tetapi juga header apa pun yang digunakan untuk tujuan seperti ini
  • Misalnya, middleware Chi menentukan IP asli klien dengan terlebih dahulu memeriksa True-Client-IP, lalu hanya memakai X-Real-IP jika header itu tidak ada
    • Walaupun proxy menangani X-Real-IP dengan benar, masalah tetap bisa muncul jika penyerang mengirim True-Client-IP
  • FastCGI memisahkan header klien dan informasi tambahan dari proxy dengan pendekatan pemisahan domain
    • Keduanya sama-sama dikirim sebagai daftar parameter kunci/nilai, tetapi nama header HTTP diberi prefiks HTTP_
    • Karena itu, header yang dikirim klien tidak dapat ditafsirkan sebagai data tepercaya milik proxy

Penanganan informasi tepercaya FastCGI di Go

  • FastCGI mendefinisikan parameter standar seperti REMOTE_ADDR untuk meneruskan IP klien sebenarnya
  • net/http/fcgi di Go secara otomatis mengisi nilai ini ke RemoteAddr pada http.Request, sehingga bekerja tanpa middleware tambahan
  • Proxy juga dapat meneruskan informasi seperti apakah HTTPS digunakan, TLS cipher suite yang dinegosiasikan, atau sertifikat klien sebagai parameter nonstandar
  • Di Go, jika permintaan menggunakan HTTPS, field TLS pada Request otomatis diatur ke nilai yang tidak nil
    • Meski kosong, ini tetap berguna untuk memeriksa apakah HTTPS diwajibkan
  • Seluruh kumpulan parameter tepercaya yang dikirim proxy dapat diakses melalui fcgi.ProcessEnv

Mengapa adopsinya lambat dan keterbatasan praktisnya

  • Jika FastCGI lebih baik, mengapa tidak dipakai luas? Tampaknya kombinasi antara nama yang terasa kuno dan kurangnya kesadaran terhadap masalah keamanan reverse proxy HTTP ikut berperan
  • Watchfire sudah membahas serangan desync pada 2005 dan juga memperingatkan bahwa penyelesaiannya tidak mudah, tetapi serangan seperti ini tidak benar-benar mendapat perhatian selama lebih dari 10 tahun
  • FastCGI masih layak dipakai hingga sekarang, dan di SSLMate telah digunakan dalam produksi selama lebih dari 10 tahun
  • Namun, sebagai teknologi lama, ia juga punya kelemahan
    • Tidak diperbarui untuk mendukung WebSockets
    • Ekosistem alatnya kurang memadai
    • Misalnya, curl mendukung FTP, Gopher, bahkan SMTP, tetapi tidak bisa mengirim permintaan FastCGI
  • Saat server FastCGI Go dibenchmark di belakang beberapa reverse proxy, sebagian workload menunjukkan throughput lebih rendah dibanding HTTP/1.1 atau HTTP/2
    • Ini dipandang bukan sebagai batasan bawaan protokol, melainkan akibat jalur kode FastCGI yang belum dioptimalkan seperti HTTP

Penilaian akhir

  • Jika WebSockets tidak dibutuhkan dan performa saat ini sudah cukup, FastCGI masih merupakan pilihan yang layak
  • Bahkan jika nanti muncul bottleneck, penulis menilai menambah hardware lebih baik daripada menanggung kompleksitas dan mimpi buruk keamanan dari reverse proxy HTTP

2 komentar

 
rtyu1120 2026-04-30

Komentar Twisted tentang FastCGI yang saya temukan di komentar Lobsters cukup mengesankan https://web.archive.org/web/20160723091923/…

 
GN⁺ 2026-04-30
Opini Hacker News
  • Saya setuju dengan maksud tulisannya. Untuk penggunaan seperti ini, menurut saya FastCGI lebih baik daripada HTTP
    Saya juga ingin memperkenalkan protokol bernama WAS(Web Application Socket). Enam belas tahun lalu, di tempat kerja saya merasa FastCGI pun belum cukup baik, jadi saya merancangnya sendiri
    Alih-alih framing socket utama, ia memakai 1 control socket dan 2 pipe untuk body request/response mentah, dan baik aplikasi WAS maupun web server bisa memanfaatkan splice() pada pipe tersebut
    Tidak perlu framing, pembatalan request juga dimungkinkan, dan tiga file descriptor selalu bisa dipulihkan
    Selama bertahun-tahun ini dipakai di aplikasi internal dan lingkungan web hosting, dan saya juga menulis sendiri PHP SAPI-nya. Cukup banyak situs web yang secara internal berjalan di atas WAS
    Semuanya open source
    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 dan HTTP bukan berada pada lapisan yang sama
      HTTP dipakai untuk pengiriman data antara dua ujung seperti browser dan server, sedangkan FastCGI dipakai untuk memproses data itu antara server dan aplikasi
      Saya baru saja membaca sekilas artikelnya, dan penulis tampaknya menulis dengan cara yang membingungkan seolah keduanya saling dapat menggantikan. Padahal sama sekali tidak begitu
      Sebagai catatan, saya juga sudah memakai fcgi selama 10 tahun untuk layanan pelanggan web
  • Artikel ini justru menarik karena banyak yang terlewat
    Saat perdebatan FastCGI vs. SCGI vs. HTTP sedang panas, saya mendirikan startup Web2.0 dan menyusun sendiri stack frontend-nya, dan pada akhirnya HTTP menang karena kesederhanaannya
    Karena HTTP memang sudah harus ditangani di gateway, memakai itu apa adanya berarti tidak perlu menambahkan protokol lain ke stack, dan ini membuat konfigurasi seperti menaruh reverse proxy di beberapa lapis atau memisahkan perhatian lintas-fungsi seperti autentikasi, sesi, terminasi SSL, dan filtering DDoS ke server per peran menjadi sangat mudah
    Di lingkungan pengembangan, kita bisa langsung terhubung ke app server lewat HTTP, dan di produksi reverse proxy yang menangani SSL, autentikasi, dan deteksi penyalahgunaan, sehingga app server yang sama bisa dipakai ulang begitu saja
    Saat itu, nginx juga jauh lebih cepat dan stabil daripada kebanyakan modul FastCGI/SCGI. Awalnya saya memakai HTTP -> Lighttpd -> FastCGI -> Django, tapi ternyata jauh lebih cepat kalau langsung pakai nginx
    Penggunaan HTTP bekerja seperti End-to-End Principle versi web. Maksudnya, jaringan dan protokol seharusnya tidak peduli pada isi yang dibawa, dan logika aplikasi seharusnya berada di ujung, bukan di node jaringan yang memfilter atau mengalihkan
    Namun, inti yang ditunjukkan artikel ini adalah bahwa dari sisi keamanan, sering kali lebih baik mengikuti prinsip least privilege. Hanya komunikasi yang sudah diperkirakan yang boleh lolos lewat allowlist agar kita tidak tanpa sadar ikut berkontribusi pada kompromi di titik lain
    Pada akhirnya ada ketegangan antara keduanya. E2E memberi fleksibilitas, tetapi fleksibilitas itu juga memperbesar peluang penyalahgunaan, sedangkan PoLP memberi keamanan, tetapi membuat sistem hanya bisa melakukan hal-hal yang sudah dirancang sehingga lebih sulit beradaptasi dengan kebutuhan baru
    [1] https://en.wikipedia.org/wiki/End-to-end_principle
    [2] https://en.wikipedia.org/wiki/Principle_of_least_privilege

    • Menurut saya analogi itu tidak terlalu cocok, terutama dalam konteks connection caching dan multiplexing
      Jika gateway perantara memultiplex banyak request HTTP ke satu kanal HTTP lain, dan kanal itu tersambung langsung ke listening service tanpa didemultiplex sebelum socket aplikasi, maka itu pada dasarnya merusak logika end-to-end dalam banyak hal
      Analogi itu baru agak masuk jika simetri koneksi 1:1 tetap dipertahankan
      Menurut saya, kerentanan reverse proxy semuanya langsung berasal dari pelanggaran terhadap end-to-end
      Jika analogi itu benar, maka pengiriman SMTP yang melewati banyak MX juga harus dianggap end-to-end, padahal kenyataannya tidak, dan ia juga menimbulkan masalah mirip reverse proxy, misalnya desinkronisasi batas pesan
      Saya paham maksud untuk memetakan request HTTP ke pesan, tetapi itu cepat runtuh karena semantik TCP·HTTP yang nyata dan berbagai detail protokol
      Prinsip end-to-end tidak membolehkan kita memperlakukan semantik secara serampangan. Ia menuntut disiplin yang sangat ketat soal manajemen state dan batas lapisan transport. Sesuatu yang kira-kira mirip end-to-end bukanlah end-to-end
    • Bagi pengembang web app, HTTP semantics itu berguna, tetapi wire protocol HTTP sendiri buruk
      Misalnya, multiplexing bahkan belum ada sebelum HTTP 2.0, jadi memakai HTTP apa adanya untuk komunikasi antara reverse proxy dan backend itu sangat boros
      Ada juga masalah keamanan. Parser yang berbeda bisa menafsirkan batas akhir request secara berbeda
      Google juga sejak lama membungkus HTTP antara front web server dan aplikasi dengan protokol internal mereka, Stubby
      Jauh lebih cepat daripada wire protocol HTTP dan fiturnya juga lebih banyak. Biasanya ini berlebihan untuk kebanyakan perusahaan, tetapi pada skala besar biaya membuat wire protocol lain beserta tooling di sekitarnya sendiri menjadi cukup layak
    • Menerapkan end-to-end principle di dalam data center tidak terlalu bermakna, dan seperti yang ditunjukkan artikel ini, justru memungkinkan perilaku yang tidak aman
    • Hal yang saya benci dari nginx adalah dokumentasi-nya. Rasanya nyaris tidak berguna
      httpd juga pada titik tertentu bergerak ke arah yang membuat konfigurasi makin sulit, dan saya meninggalkannya saat mereka tiba-tiba mengganti format konfigurasinya
      Sebenarnya saya bisa saja beradaptasi, tetapi sebagai gantinya saya pindah ke lighttpd, lalu setelah itu ruby mengotomatisasi pembuatan konfigurasi sehingga secara teknis saya sebenarnya bisa kembali ke httpd
      Meski begitu, saya tetap tidak ingin kembali. Jika Anda pengembang web server, Anda seharusnya berhati-hati terhadap keputusan yang memaksa pengguna menyesuaikan diri dengan format baru
      Kalau memang akan mengganti format konfigurasi untuk keputusan yang sebenarnya sederhana, setidaknya sediakan opsi tambahan seperti konfigurasi yaml agar pengguna tidak tiba-tiba dipaksa memakai format konfigurasi bergaya if-clause yang baru
  • Sekarang, setelah WHATWG streams tersebar luas di browser, cukup mudah mengimplementasikan sesuatu yang mirip WebSocket sendiri di atas request HTTP berumur panjang
    Cukup kirim byte stream dan tambahkan header di depan tiap pesan; dalam banyak kasus satu nilai panjang saja sudah cukup
    Ada juga keuntungannya. Tidak seperti WebSocket, ini tidak memerlukan jalur khusus terpisah di lapisan server, bisa memakai backpressure, mendapat peningkatan HTTP/2·HTTP/3 secara gratis, dan overhead framing-nya juga lebih rendah
    Namun AFAIK masih belum didukung untuk terus men-streaming body request sambil sekaligus menerima response, jadi untuk streaming dua arah penuh tetap butuh dua request

  • Saya baru menemukan kembali plain CGI yang lama, dan ternyata sangat cocok untuk membiarkan pengguna melakukan vibe code pada halaman kustom di platform kami [1]
    Fitur bawaan kami mencakup task list dan data viewer, tetapi pengguna sering menginginkan kustomisasi yang jauh lebih rinci, seperti tampilan Kanban atau dashboard kustom dengan filter data dan chart
    Di kotak ini ada coding agent, jadi alih-alih kami membuat report builder tradisional, pengguna bisa langsung membuat sendiri apa yang mereka inginkan dalam bentuk kode
    Go stdlib punya dukungan yang bagus baik di sisi server maupun user space, dan jika coding agent membuat page-name/main.go lalu berkomunikasi lewat CGI, server tinggal mendelegasikan request ke sana
    Karena skala data dan pageview semuanya masih person scale, optimasi seperti FastCGI sama sekali tidak terlalu dibutuhkan
    Di era agent, teknologi lama terasa baru lagi

    1. https://housecat.com
    • Berbeda dari FastCGI, CGI meneruskan header HTTP sebagai environment variable, jadi hati-hati karena ini punya jebakan yang cukup besar: https://httpoxy.org/
      Implementasi server CGI di Go aman pada bagian itu karena tidak menetapkan $HTTP_PROXY, tetapi saya tetap tidak suka dengan cara CGI memakai environment variable
  • Di sisi reverse proxy, kebanyakan pekerjaannya sederhana, jadi memakai fitur bawaan Nginx biasanya sudah cukup
    Meski begitu, jika butuh sesuatu yang lebih kompleks, ide untuk memakai FastCGI sepertinya tidak akan terpikir oleh saya
    Sekitar 10 tahun lalu saya sempat sedikit memakai FastCGI untuk menjalankan sebagian kode C++ di web, tetapi setelah itu hampir tidak pernah lagi

    • Sekarang embedded server jauh lebih umum
      Cukup tanamkan langsung HTTP server di dalam aplikasi, lalu lakukan sendiri apa yang diperlukan tanpa gateway
  • Konfigurasi PHP/Apache yang didistribusikan di keluarga Red Hat adalah FPM(FastCGI Process Manager)
    Saya tidak tahu apakah FastCGI juga dipakai di tempat lain di distribusi RHEL
    $ rpm -qi php-fpm | grep ^Summary
    Summary : PHP FastCGI Process Manager

  • Ada juga uwsgi protocol
    Ini pada dasarnya juga mirip RPC untuk hampir semua hal

  • FCGI juga merupakan sistem orkestrasi
    Saat beban naik, ia menyalakan lebih banyak task server, saat beban turun ia mematikannya, dan jika task mati ia menyalakan salinan baru
    Semacam Kubernetes untuk satu sistem

    • Dalam pengalaman saya, fitur itu tidak terlalu bagus
      Kedengarannya memang bagus, tetapi sering terjadi sistem baik-baik saja saat beban rendah, lalu kehabisan memori ketika beban tinggi datang karena ia mulai membuat lebih banyak worker
      Karena itu, biasanya lebih baik memakai jumlah worker statis
      Namun crash recovery tetap berguna bila memang dibutuhkan
    • Kami juga memakainya persis seperti itu
  • Cukup luangkan sejenak untuk mengagumi keabsurdan header HTTP
    Jika kita hanya memakai X-Real-IP saat True-Client-IP tidak ada, maka bahkan jika proxy sudah mengisi X-Real-IP dengan benar, penyerang tetap bisa lolos hanya dengan mengirim header True-Client-IP
    Ada X-Forwarded-For, X-Real-IP, sampai header kustom yang berbeda-beda untuk tiap CDN; sebagian berupa daftar yang dipisahkan koma dan biasanya bahkan ikut menambahkan IP LB kita sendiri yang tidak ada gunanya
    Saya tahu kenapa bisa begitu, tetapi itu sama sekali tidak membantu
    Lebih buruk lagi, semua header ini juga bisa disisipkan oleh user-agent yang berniat jahat. Rasanya seperti tidak pernah ada kesepakatan tentang bagaimana server tepercaya seharusnya meneruskan informasi penting di sepanjang pipeline
    Kekacauan ini juga sangat cocok dipasangkan dengan keabsurdan header User-Agent
    Di situ Apple mendorong semuanya lebih jauh lagi dengan dalih privasi, sampai mengirim informasi palsu total, misalnya versi OS bohong dan omong kosong serupa

  • Ada banyak benarnya dalam argumen ini, tetapi FastCGI mewarisi kehilangan informasi dari CGI/1.1 pada bagian seperti PATH_INFO
    URL decoding dipaksakan sehingga encoded slash seperti %2F tidak bisa direpresentasikan
    Tergantung implementasinya, // di path kadang juga digabung menjadi /, walau ini juga masalah yang ada di banyak implementasi HTTP
    Dari sisi daya ekspresi, ini lebih lemah daripada HTTP, dan apakah perbedaan itu penting atau tidak tergantung aplikasinya
    Saya pribadi lebih suka penanganan URL yang presisi