Kodeloka
  1. Kodeloka
  2. Kelas Nginx
  3. Materi

3 · TLS & Keamanan · Modul 6 dari 8

Pembatasan Laju & Perlindungan

Melindungi hulu dari lonjakan, penyalahgunaan, dan permintaan berukuran ganjil — dengan algoritma yang perlu dipahami dulu.

Membatasi Laju Permintaan

http {
    limit_req_zone $binary_remote_addr zone=umum:10m rate=10r/s;
    limit_req_zone $binary_remote_addr zone=masuk:10m rate=5r/m;

    server {
        location / {
            limit_req zone=umum burst=20 nodelay;
        }

        location /login {
            limit_req zone=masuk burst=3;
            limit_req_status 429;
        }
    }
}

$binary_remote_addr dipakai alih-alih $remote_addr karena bentuk binernya hanya 4 byte untuk IPv4, bukan belasan byte sebagai teks. Zona 10 MB dengan demikian sanggup melacak sekitar 160.000 alamat.

Ember Bocor dan Arti burst

Nginx memakai algoritma leaky bucket. Dengan rate=10r/s, Nginx tidak menghitung "10 permintaan per detik" melainkan memaksa jarak 100 milidetik antar permintaan. Permintaan kesebelas dalam satu detik yang sama langsung ditolak dengan 503.

limit_req zone=umum;                    # kaku — tanpa toleransi sama sekali
limit_req zone=umum burst=20;           # 20 boleh mengantre, dilayani berjarak
limit_req zone=umum burst=20 nodelay;   # 20 boleh langsung, kuota diisi ulang
⚠️ burst tanpa nodelay membuat halaman terasa macet

Satu halaman web memuat puluhan aset sekaligus. Dengan burst=20 tanpa nodelay, permintaan tidak ditolak tetapi diantrekan dan dilepas satu per 100 ms — aset ke-20 baru sampai dua detik kemudian. Pengguna melihat halaman yang termuat merangkak. Menambahkan nodelay melayani lonjakan itu segera sementara laju rata-rata tetap terjaga.

Membatasi Koneksi Serentak

limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name         zone=persrv:10m;

location /unduh/ {
    limit_conn perip   3;
    limit_conn persrv  100;
    limit_rate_after   10m;      # 10 MB pertama penuh
    limit_rate         500k;     # sesudahnya dibatasi
}

Batas Ukuran dan Waktu

client_max_body_size    10m;     # tolak unggahan lebih besar
client_body_timeout     12s;
client_header_timeout   12s;
client_body_buffer_size 16k;
large_client_header_buffers 4 8k;

send_timeout            10s;
keepalive_timeout       65s;
🚫 413 Request Entity Too Large di tengah unggahan

Nilai bawaan client_max_body_size hanya 1 MB. Unggahan foto biasa langsung ditolak, dan kesalahannya muncul di Nginx sebelum permintaan pernah sampai ke aplikasi — sehingga penanganan kesalahan di aplikasi tidak pernah berjalan dan log aplikasi tampak bersih. Selalu periksa nilai ini lebih dulu saat unggahan gagal tanpa jejak.

Menyembunyikan Informasi Versi

server_tokens off;                       # sembunyikan versi di header dan halaman galat

proxy_hide_header X-Powered-By;
proxy_hide_header X-AspNet-Version;

add_header X-Frame-Options           "SAMEORIGIN" always;
add_header X-Content-Type-Options    "nosniff"    always;
add_header Referrer-Policy           "strict-origin-when-cross-origin" always;
💡 Kenapa always penting

Tanpa always, add_header hanya diterapkan pada balasan sukses — 200, 201, 301, 304. Balasan galat seperti 404 dan 500 keluar tanpa header keamanan tersebut. Karena halaman galat juga dapat dieksploitasi untuk clickjacking atau sniffing tipe konten, tambahkan always pada seluruh header keamanan.

Menyaring Berdasarkan Alamat

location /admin/ {
    allow 10.0.0.0/8;
    allow 192.168.1.0/24;
    deny  all;
}
⚠️ Di belakang CDN, $remote_addr adalah alamat CDN

Aturan allow dan deny membaca $remote_addr. Bila Nginx berdiri di belakang Cloudflare atau penyeimbang beban, nilai itu adalah IP perantara — sehingga aturan menyaring hal yang salah dan pembatasan laju menghitung seluruh dunia sebagai satu klien. Konfigurasikan set_real_ip_from beserta real_ip_header lebih dulu.

set_real_ip_from 173.245.48.0/20;
real_ip_header   CF-Connecting-IP;
real_ip_recursive on;