Kamis pagi, satu pesan masuk dari agensi yang dua minggu sebelumnya baru resmi onboarding lewat akun multi-seat yang kuceritakan di sini: dashboard tracker langganan mereka menampilkan galat 429 "Too Many Requests" hampir setiap kali mereka membuka laporan klien. Ini bukan pengguna gratisan iseng. Ini akun berbayar terbesar yang pernah kupunya, baru dua minggu jalan, dan sistem yang kubangun sendiri untuk melindungi API dari penyalahgunaan justru mengusir mereka duluan.
Limiter yang Dibuat untuk Musuh yang Salah
Rate limiter itu kupasang tiga bulan lalu, jauh sebelum agensi ini masuk, setelah aku menemukan pola scraping mencurigakan di endpoint publik yang menampilkan status langganan — ratusan request per menit dari rentang IP yang sama, jelas bot, bukan manusia. Solusinya waktu itu terasa cukup: hitung request per alamat IP lewat Redis, INCR dengan EXPIRE 60 detik, dan blokir kalau lewat 100 request per menit dari satu IP. Cepat dipasang, langsung menghentikan scraping-nya, dan aku pindah ke masalah lain tanpa menengok lagi bagaimana limiter ini akan berperilaku begitu ada pelanggan sungguhan dengan pola trafik yang berbeda dari bot.
Yang tidak kupikirkan waktu itu: limiter ini berjalan di lapisan paling depan, sebelum request bahkan sempat diperiksa API key atau status langganannya. Setiap request, entah dari bot anonim atau dari pelanggan premium yang sudah login, masuk ke penghitung IP yang sama duluan. Selama tiga bulan itu bukan masalah, karena semua pelangganku individu, satu orang satu koneksi rumah, jauh di bawah 100 request per menit.
Kenapa Baru Ketahuan Sekarang
Agensi ini berbeda: sekitar 35 orang di satu kantor, semuanya di belakang satu jaringan kantor dengan satu alamat IP publik keluar, seperti kebanyakan kantor kecil-menengah. Begitu mereka mulai kerja normal — buka dashboard, refresh laporan klien, beberapa tab browser per orang, ditambah polling otomatis dari fitur auto-refresh yang memang sudah lama ada di produk — total request dari satu alamat IP itu gampang tembus 150-200 per menit. Bukan karena satu orang nakal, tapi karena 35 orang normal kebetulan berbagi satu pintu keluar internet.
Limiter yang kupasang untuk mengusir bot itu sama sekali tidak tahu bedanya. Dari sudut pandang Redis, satu IP dengan 200 request per menit terlihat identik entah itu scraper jahat atau kantor sungguhan yang sedang bekerja. Dan karena pemeriksaan IP ini terjadi sebelum sistem sempat membaca bahwa akun ini punya kuota premium 5.000 request per hari yang jauh dari terlampaui, kuota premium itu tidak pernah relevan — mereka sudah diblokir di gerbang pertama.
Aku sempat curiga awalnya ini soal kuota harian mereka yang terlampaui, sampai aku cek dashboard billing dan lihat mereka baru pakai kurang dari 8% dari jatah harian. Baru setelah menelusuri log Redis dan menyaring key rate-limit berdasarkan IP, aku sadar semua 429 itu datang dari satu alamat IP yang sama, jauh sebelum request itu bahkan sampai ke pemeriksaan kuota akun.
Menata Ulang Urutan Pemeriksaan
Perbaikannya bukan menaikkan angka 100 jadi lebih besar — itu cuma menunda masalah yang sama untuk agensi berikutnya yang lebih besar, atau membuka celah lagi buat bot yang lebih sabar. Yang salah adalah urutannya: limiter anonim berbasis IP seharusnya cuma berlaku untuk request yang benar-benar belum terautentikasi, bukan diterapkan rata ke semua orang lebih dulu.
Aku susun ulang jadi dua lapis yang jalan berurutan. Kalau request punya API key atau sesi login yang valid, ia langsung masuk ke limiter berbasis ID akun dengan kuota sesuai paketnya — bukan lagi dihitung sebagai bagian dari trafik IP publik itu. Limiter IP lama tetap ada, tapi sekarang hanya menyaring request yang benar-benar anonim, sebelum sempat tahu siapa pengirimnya. Praktiknya, satu baris urutan pemeriksaan di middleware yang kubalik: cek identitas dulu, baru terapkan limiter yang sesuai kelasnya, bukan sebaliknya.
Aku juga menambahkan satu query cepat ke log Redis lama sebelum deploy: mengecek apakah ada akun berbayar lain yang diam-diam ikut kena, hanya belum melapor. Ada satu, sebuah tim kecil di kampus yang berbagi wifi lab, dengan pola 429 yang sama tapi dalam skala lebih kecil sehingga belum sempat mereka sadari sebagai masalah, bukan cuma dianggap koneksi lambat.
Takeaway
Kode yang paling jarang kutengok lagi biasanya kode yang paling dulu kutulis dengan asumsi paling sempit — limiter ini dibuat untuk satu musuh spesifik (bot scraping individu) dan diam-diam mewarisi asumsi itu selama tiga bulan sampai bentuk trafik yang sebenarnya berubah. Pelajarannya bukan "jangan pasang rate limiter", tapi: begitu ada lapisan pertahanan yang memutuskan boleh-tidaknya request sebelum sistem tahu siapa pengirimnya, itu perlu ditinjau ulang setiap kali profil penggunamu berubah — dari individu di rumah masing-masing, jadi tim yang berbagi satu jaringan kantor. Kuota per akun harus selalu diperiksa lebih dulu daripada batas anonim, bukan belakangan.
Sumber gambar: Ales Nesetril di Unsplash Sumber gambar: Austin Distel di Unsplash Sumber gambar: Domaintechnik di Unsplash
The conversation 0
No comments yet. Start the conversation.