Login endpoint adalah target utama: brute force, credential stuffing, dan enumeration. Rate limiting adalah lapisan pertahanan sebelum password hash bahkan diperiksa.
Yang dibatasi:
| Layer | Limit | Tujuan |
|---|---|---|
| Per IP | 10 req/menit | Anti brute force dari satu sumber |
| Per username | 5 req/15 menit | Cegah lockout eksternal |
| Per IP + username | 3 req/menit | Kombinasi paling sempit |
| Global | 10k req/menit | Anti DoS |
Algoritma umum:
1. Fixed Window (paling sederhana):
const key = `login:${ip}:${Math.floor(Date.now() / 60000)}`;
const count = await redis.incr(key);
await redis.expire(key, 60);
if (count > 10) throw new RateLimitError();
Masalah: penyerang bisa kirim 20 request di detik ke-59 dan ke-00.
2. Sliding Window (lebih akurat):
function allowRequest(key, now, windowMs, maxRequests) {
requests[key] = (requests[key] || []).filter(
t => now - t < windowMs
);
if (requests[key].length >= maxRequests) return false;
requests[key].push(now);
return true;
}
Simpan timestamp tiap request. Saat dicek, hanya hitung yang masuk window terakhir.
3. Token Bucket (burst-friendly):
Bucket berisi N token. Setiap request konsumsi 1 token. Token regenerate R per detik. Jika bucket kosong → tolak.
Bagus untuk API publik — user boleh burst sebentar, asal rata-rata masih di bawah rate.
Response yang tepat:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1700000060
Implementasi cerdas untuk login:
async function handleLogin(req, res) {
if (!globalLimiter.allow()) return res.status(429).end();
if (!ipLimiter.allow(req.ip)) return res.status(429).end();
const { email, password } = req.body;
if (!userLimiter.allow(email)) return res.status(429).end();
const user = await authenticate(email, password);
if (!user) {
userLimiter.recordFail(email);
return res.status(401).end();
}
return res.json({ token: issueToken(user) });
}
Jangan:
- Berbasis cookie client-side saja (bisa di-clear)
- Hanya per IP (pakai VPN/proxy bypass)
- Tanpa window timeout (memory leak)
Distributed rate limiting:
Di multi-server, rate limiter harus shared — gunakan Redis dengan atomic operations (INCR + EXPIRE) atau Redis Cell module.