CORS di Produksi
CORS di Produksi
Halaman ini adalah dokumentasi, bukan perubahan backend. Kode
api-gateway saat ini masih mengirim header CORS permisif. Perubahan
backend yang sebenarnya dilacak sebagai item BE1 di
docs-site/SCOPE.md — "Backend follow-up register" Section 4 —
dan harus dikerjakan sebelum Try-It playground di
docs-chat.misindo.id dibuka ke api-gateway produksi.
State saat ini
api-gateway memasang satu CORS layer global di router utama, tepatnya
di crates/api-gateway/src/main.rs:253:
Code
CorsLayer::permissive() dari tower_http menghasilkan header yang
mengizinkan origin manapun, method manapun, dan header
apapun. Secara konkret, respons preflight yang keluar kurang lebih:
Code
Cocok untuk pengembangan lokal — frontend di
http://localhost:4000, curl dari mana saja, Try-It playground di
http://localhost:5000 semuanya langsung jalan tanpa konfigurasi.
Tapi tidak cocok untuk produksi.
Kenapa permisif di produksi berbahaya
- Cross-origin credential leakage. Karena
Allow-Origindipasang ke*, browser tidak akan mengirimAuthorization: Bearer ...secara otomatis pada fetch cross-origin (spec CORS memblokir kombinasiAllow-Origin: *+ kredensial). Tapi banyak klien membaca JWT darilocalStoragedan mengirimnya manual di header — kebijakan "terima semua origin" berarti situs pihak ketiga yang berhasil mencuri token bisa langsung memanggil endpoint kita. - CSRF surface expansion. Endpoint idempotent yang hanya terlindungi oleh cookie session mudah di-replay dari tab manapun.
- Meng-ajarkan pola yang salah. Dokumentasi dan tutorial yang
mencontohkan
CorsLayer::permissive()di produksi merupakan anti-pattern — kita tidak mau itu muncul di developer onboarding OmniStream.
Token bucket rate limiter (tower_governor, 60 req/menit per IP —
lihat
developer/error-dan-rate-limit)
tidak menyelesaikan ini. Rate limit membatasi volume, bukan
origin.
Pola allowlist yang direkomendasikan
Ganti CorsLayer::permissive() dengan allowlist yang eksplisit,
dibangun dari variabel lingkungan yang sudah dikenal konfigurasi
(FRONTEND_URL) plus origin docs-site:
Code
Hal-hal yang membuat pola ini aman:
allow_origineksplisit. Hanya dua origin yang valid: frontend utama (dari env) dan dokumentasidocs-chat.misindo.id. Semua origin lain mendapat preflight 403.allow_methodseksplisit. Tidak ada wildcard.TRACEdanCONNECTotomatis tertolak.allow_headersterkurasi. Hanya header yang benar-benar dipakai klien (Authorization,Content-Type,Accept). Klien tidak bisa memaksa header custom yang belum direview.allow_credentials(true). Aman karenaallow_originsudah bukan wildcard. Browser akan mengirim cookie/Authorization sesuai spec.max_age600 detik. Mengurangi jumlah preflight tanpa memberi cache yang berlebihan — cocok untuk iterasi cepat saat debugging.
Kalau anda menjalankan api-gateway sendiri
Selama backend belum di-update, tiga jalur yang aman untuk produksi:
- Taruh di belakang reverse proxy yang sama domain-nya dengan
frontend (mis. Nginx yang menyajikan frontend dan melakukan
proxy_passkeapi-gatewaypada path/api). Dengan begitu browser melihat semuanya same-origin dan CORS tidak pernah dieksekusi. Lihatdeveloper/self-hosting/reverse-proxy. - Jangan paparkan
api-gatewaylangsung ke internet. Akses hanya dari VPS/LAN yang sama; buka port publik hanya untuk Nginx frontend-nya. - Tunda membuka Try-It playground di
docs-chat.misindo.idsampai BE1 selesai. Sementara itu, tetap gunakan Try-It untuk mengirim request kehttp://localhost:3000dari dev environment (localhost-to-localhost tidak mempedulikan CORS ketat).
Roadmap BE1
Item BE1 di docs-site/SCOPE.md Section 4 ber-status HIGH priority.
Definition of Done:
CorsLayer::permissive()diganti dengan allowlist berbasis env + origin docs.- Tambahkan unit test di
api-gatewayyang memverifikasi origin yang tidak terdaftar dapat preflight 403 dan origin yang terdaftar mendapat 200 dengan header yang benar. - Update dokumentasi ini untuk mencoret peringatan bagian atas dan menunjukkan state baru sebagai "current".
Selama hal di atas belum terjadi, halaman ini berfungsi ganda: referensi bagi operator, dan checklist bagi pengembang backend yang akan mengerjakan BE1.