Keamanan Siber

IP Klien di Balik Reverse Proxy - Percayai Koneksi Sebelum Header

IP Klien di Balik Reverse Proxy - Percayai Koneksi Sebelum Header

IP Klien di Balik Reverse Proxy - Percayai Koneksi Sebelum Header

Aplikasi di balik reverse proxy menghadapi pilihan yang serba tidak nyaman. Jika hanya mencatat peer jaringan, semua request mungkin terlihat berasal dari proxy. Jika menerima header seperti X-Forwarded-For tanpa kebijakan kepercayaan, klien mungkin dapat memilih alamat yang muncul di log, rate limit, atau aturan akses.

Karena itu, pertanyaan yang berguna bukan sekadar, “Header mana yang berisi IP asli?” Pertanyaannya adalah: mesin mana yang mengirimkan request ini, mesin mana yang diizinkan menambahkan informasi forwarding, dan di mana rantai itu berhenti layak dipercaya?

Artikel ini menyusun model tersebut untuk deployment Nginx kecil. Konfigurasinya sengaja dibuat generik. Alamat proxy, jalur jaringan, dan header khusus provider harus disesuaikan dengan arsitektur sebenarnya, bukan disalin begitu saja.

Alamat Koneksi dan Header Adalah Bukti yang Berbeda

Pada koneksi langsung, Nginx dapat melihat alamat peer yang membuka socket. Ketika reverse proxy ditempatkan di depan, peer terdekat itu berubah menjadi proxy. Alamat klien awal tidak lagi tersedia pada layer jaringan yang sama, sehingga proxy biasanya membawanya melalui metadata HTTP.

X-Forwarded-For adalah header request de-facto yang digunakan secara luas. IETF menstandarkan field Forwarded yang berkaitan di RFC 7239, tetapi field lama berawalan X masih umum. Tidak satu pun nama tersebut mengautentikasi nilainya. Browser, script, perantara yang salah konfigurasi, atau klien berbahaya juga dapat mengirim field forwarding.

Perbedaan itu menghasilkan aturan praktis: kepercayaan dimulai dari koneksi langsung, bukan dari teks paling kiri di dalam header. Metadata forwarding baru berguna ketika peer terdekat merupakan proxy yang memang diharapkan dan proxy tersebut memiliki kebijakan jelas untuk membuat, mengganti, atau memperpanjangnya.

Baca Rantai Proxy dari Sisi yang Dipercaya

Bayangkan sebuah request sampai ke origin dengan field berikut:

X-Forwarded-For: 198.51.100.23, 10.20.0.8

Urutan konvensional berjalan dari alamat paling awal di kiri menuju proxy yang lebih akhir di kanan. Namun, “paling kiri” tidak berarti “terverifikasi”. Klien bisa saja mengirim nilai yang sudah ada sebelum proxy pertama yang dikendalikan menambahkan informasi apa pun.

Untuk keputusan yang sensitif terhadap keamanan, evaluasi berjalan ke arah sebaliknya. Mulailah dari socket peer, pastikan peer itu termasuk proxy tepercaya yang didefinisikan secara sempit, lalu telusuri daftar dari kanan ke kiri selama alamatnya masih tepercaya. Alamat pertama di luar kelompok tepercaya tersebut adalah alamat klien terdekat yang masih dapat dipertahankan secara masuk akal. Seperti diperingatkan oleh referensi X-Forwarded-For MDN, alamat itu mungkin milik perantara yang tidak dipercaya, bukan perangkat milik orang tersebut. Meski begitu, itulah batas setelah origin tidak lagi memiliki dasar untuk memercayai klaim tambahan.

Ada dua cara umum untuk menjelaskan batas tersebut:

  • Jumlah hop proxy yang tetap, sederhana tetapi rapuh ketika request dapat melewati jalur dengan panjang berbeda.
  • Daftar eksplisit alamat atau rentang proxy tepercaya, yang biasanya memodelkan jalur yang berubah dengan lebih aman jika daftar itu terus dijaga akurat.

Alamat privat tidak otomatis tepercaya, dan alamat publik tidak otomatis berbahaya. Kepercayaan berasal dari kendali atas rute dan proxy, bukan karena alamatnya terlihat familier.

Nyatakan Batas dengan Nginx Real IP

Real IP module Nginx dapat mengganti alamat klien efektif dengan nilai yang diberikan proxy yang dikenal. Modul ini tidak aktif secara default pada setiap build upstream, jadi periksa binary yang terpasang sebelum memakai directive-nya:

nginx -V 2>&1

Cari --with-http_realip_module, atau pastikan bagaimana paket sistem operasi menyediakan modul tersebut. Host Debian yang dipakai untuk memvalidasi sintaks artikel ini melaporkan Nginx 1.26.3 dengan opsi build tersebut. Hasil lokal ini hanya memastikan bahwa contoh dapat diparse pada host itu; hasil tersebut tidak menjelaskan paket atau topologi proxy di server lain.

Misalkan satu load balancer internal di 10.20.0.10 adalah satu-satunya peer yang memang ditujukan bagi origin dan load balancer tersebut memelihara X-Forwarded-For. Kebijakan awalnya adalah:

set_real_ip_from 10.20.0.10;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

Setiap baris memiliki tugas terpisah:

  • set_real_ip_from menyebutkan alamat atau CIDR yang informasi penggantinya akan diterima Nginx. Nilainya seharusnya menunjuk proxy terkendali yang benar-benar digunakan, bukan semua alamat melalui aturan praktis seperti 0.0.0.0/0.
  • real_ip_header memilih field yang membawa alamat pengganti. Default Nginx adalah X-Real-IP; contoh ini memilih X-Forwarded-For secara eksplisit.
  • real_ip_recursive on meminta Nginx bergerak mundur melalui rantai yang diberikan dan memilih alamat terakhir yang tidak tepercaya, alih-alih sekadar mengambil nilai terakhir.

Setelah pemrosesan berhasil, $remote_addr berisi alamat efektif. Nginx menyimpan peer koneksi asli di $realip_remote_addr. Mencatat keduanya selama rollout membuat keputusan itu terlihat:

log_format proxy_path
    '$remote_addr via $realip_remote_addr "$request"';

access_log /var/log/nginx/access.log proxy_path;

Contoh ini memakai alamat privat hipotetis. Konfigurasi nyata memerlukan setiap jalur proxy terdekat yang sah, termasuk IPv6 jika berlaku, dan tidak boleh menyertakan rentang yang tidak berkaitan.

Edge Proxy dan Origin Memiliki Tugas Berbeda

Jika Nginx terpapar langsung kepada klien, socket peer-nya sudah menjadi alamat yang dapat diamati. Nginx tidak perlu memercayai header forwarding dari klien hanya untuk memperoleh alamat tersebut. Jika edge Nginx kemudian meneruskan request ke service lain, proxy module dapat meneruskan rantainya:

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

Service downstream seharusnya memercayai field ini hanya karena peer langsungnya adalah instance Nginx yang dikendalikan tersebut. Service itu tidak semestinya menerapkan aturan berbeda secara mandiri, misalnya “selalu ambil nilai pertama yang dipisahkan koma”. Satu layer sebaiknya menetapkan alamat efektif, kemudian layer berikutnya menggunakan keputusan tersebut di bawah batas yang didokumentasikan sama.

CDN membentuk susunan yang berbeda. Sebagai contoh, dokumentasi Cloudflare menjelaskan bahwa origin biasanya melihat alamat Cloudflare dan menerima alamat pengunjung di CF-Connecting-IP. Panduan Nginx-nya menggabungkan field tersebut dengan rentang proxy yang dipublikasikan Cloudflare. Rentang itu dapat berubah, sehingga daftar statis yang disalin dari artikel lama bukan konfigurasi yang tahan lama.

Header dan pemeriksaan rentang sumber harus digunakan bersama. Memercayai CF-Connecting-IP dari peer mana pun akan membuat klien langsung dapat mengklaim nilai sembarang. Memercayai rentang provider yang mutakhir sambil membatasi akses origin hanya dari provider membentuk batas yang jauh lebih jelas.

Akses Langsung ke Origin Adalah Masalah Terpisah

Parsing header yang benar tidak memaksa traffic melewati CDN, load balancer, atau WAF. Jika alamat origin tetap dapat dijangkau publik, klien mungkin terhubung dengan melewati edge yang dimaksud. Nginx dapat mengabaikan field forwarding dari peer tidak tepercaya itu, tetapi caching, filtering, dan kontrol penyalahgunaan di edge tetap berhasil dilewati.

Jika desainnya benar-benar proxy-only, tegakkan sifat itu pada batas jaringan: izinkan port origin hanya dari jaringan proxy terkendali atau rentang provider terkini, sambil tetap menyediakan jalur administrasi yang disengaja. Mekanisme firewall yang tepat berada di luar cakupan artikel ini. Pokoknya, keterjangkauan jaringan dan interpretasi header HTTP adalah dua kontrol, bukan pengganti satu sama lain.

Verifikasi Jalurnya, Termasuk Percobaan Spoofing

Sebelum me-reload service produksi, periksa konfigurasi lengkap dan validasi sintaksnya:

sudo nginx -T
sudo nginx -t

Pemeriksaan sintaks tidak dapat membuktikan model kepercayaan. Uji perilakunya melalui setiap rute yang diharapkan dan bandingkan log dua alamat:

  1. Kirim request normal melalui proxy dan pastikan alamat efektif serta peer proxy sesuai harapan.
  2. Kirim request yang memuat nilai X-Forwarded-For palsu dengan sengaja melalui jalur publik. Pastikan input dari sisi kiri yang tidak tepercaya tidak menjadi alamat keamanan.
  3. Jika rute pengujian langsung memang sengaja tersedia, kirim header palsu yang sama secara langsung. Pastikan peer yang tidak tepercaya tidak dapat membuat Nginx mengganti alamat socket-nya.
  4. Ulangi untuk setiap jalur yang sah, termasuk IPv4 dan IPv6 jika keduanya didukung.
  5. Periksa nilai yang benar-benar diterima PHP atau upstream lain; jangan berasumsi bahwa framework-nya memakai kebijakan proxy yang sama dengan Nginx.

Pengujian sebaiknya menggunakan alamat dan endpoint yang memang dimiliki untuk tujuan itu. Hindari mengunci satu-satunya jalur administrasi, dan simpan konfigurasi known-good untuk rollback. Setelah perilakunya dipahami, lakukan reload dengan prosedur aman yang sudah berlaku di situs, bukan menganggap pemeriksaan sintaks yang berhasil sebagai bukti bahwa routing sudah benar.

Jangan Menganggap Alamat IP Lebih dari Kenyataannya

Alamat klien yang dapat dipertanggungjawabkan bisa membantu log, investigasi insiden, kontrol penyalahgunaan kasar, dan input rate limit. Alamat tersebut bukan autentikasi. Carrier-grade NAT, Wi-Fi bersama, VPN, privacy relay, jaringan seluler, dan pergantian alamat biasa sama-sama melemahkan klaim bahwa satu alamat mengidentifikasi satu orang atau akun.

Aturan akses berbasis IP juga memerlukan kebijakan kegagalan. Jika metadata proxy tepercaya hilang atau cacat, memilih header lain secara diam-diam mungkin menghasilkan fail-open. Rute sensitif mungkin perlu menolak request atau kembali memakai socket peer yang terverifikasi, tergantung arsitekturnya. Pilihan tersebut harus dibuat eksplisit dan diuji.

Ada pula biaya privasi. RFC 7239 memperlakukan alamat yang diteruskan sebagai data yang berpotensi sensitif serta membahas kebocoran informasi dan privasi pengguna. Simpan hanya untuk tujuan operasional yang dinyatakan, batasi akses ke log, tentukan masa retensi, dan hindari menyalin seluruh rantai proxy internal ke response atau analytics yang tidak diperlukan.

Alamat yang Berguna Berawal dari Batas Kepercayaan yang Kecil

Jawaban paling aman untuk “Apa IP klien yang asli?” sering kali adalah bahwa sistem tidak dapat mengetahuinya dengan kepastian mutlak. Sistem dapat mengetahui sesuatu yang lebih sempit: proxy tepercaya tertentu melihat sebuah alamat dan menyampaikannya melalui jalur terkendali.

Bangun dari pernyataan sempit itu. Identifikasi proxy terdekat, percayai hanya alamatnya yang benar-benar digunakan, evaluasi informasi multi-hop dari sisi tepercaya terdekat, selaraskan paparan langsung origin dengan desain, dan catat alamat efektif serta peer asli ketika memverifikasi rollout. Setelah itu, gunakan hasilnya sebagai salah satu sinyal operasional, bukan sebagai bukti identitas.

References