--- name: rate-limit-abuse-prevention description: "Expert guide for API rate limiting, bot protection, DDoS mitigation, brute-force prevention, and abuse detection / Panduan ahli untuk rate limiting API, perlindungan bot, mitigasi DDoS, pencegahan brute-force, dan deteksi penyalahgunaan." author: "Roedy Rustam" version: "4.4.2" --- # Rate Limit & Abuse Prevention (2026 Edition) [English](#english) | [Bahasa Indonesia](#bahasa-indonesia) --- ## English ### Orchestration & Integration - **Threat Defense & Red Teaming**: `autonomous-red-teamer`, `prompt-injection-firewall`, `zero-trust-secret-vault` - **Identity & Authentication**: `authentication-identity-expert`, `compliance-gdpr-privacy-expert` - **API Architecture & Backend**: `api-design-expert`, `js-backend-expert`, `api-gateway-proxy-expert` - **Edge Infrastructure & DDoS**: `cloud-hosting-expert`, `cloudflare-workers-expert` - **SaaS Billing & Quotas**: `saas-billing`, `doku-payment-gateway`, `payment-gateway-expert` - **Lifecycle & Hardening**: `production-ready-hardener`, `brainstorming`, `zero-to-prod-orchestrator`, `session-memory-manager` ### Description Production-grade guide for protecting APIs and web applications from abuse, overuse, and attacks. Covers **rate limiting algorithms** (Token Bucket, Sliding Window), **Upstash Ratelimit**, **bot protection** (Cloudflare Turnstile, hCaptcha), **DDoS mitigation** at edge, **brute-force login prevention**, **API key management & usage quotas**, and **response headers** (X-RateLimit, Retry-After). ### Trigger Conditions Activate this skill when: - Implementing API rate limiting for public or authenticated endpoints. - Adding bot protection (CAPTCHA) to forms (login, signup, contact). - Setting up DDoS protection at the edge (Cloudflare, Vercel). - Preventing brute-force attacks on authentication endpoints. - Implementing API key issuance and usage quotas for SaaS. - Building tiered rate limits based on subscription plans. --- ### Rate Limiting Algorithm Comparison | Algorithm | Behavior | Best For | Burst Handling | |---|---|---|---| | **Fixed Window** | Resets counter at interval boundary | Simple endpoints | Allows double burst at window edge | | **Sliding Window** | Rolling window, smooth distribution | API endpoints | Smooth, no edge burst | | **Token Bucket** | Tokens refill at fixed rate | High-throughput APIs | Allows controlled bursts | | **Leaky Bucket** | Processes at fixed rate, queues excess | Stream processing | No bursts, constant rate | **Recommendation**: Use **Sliding Window** for most API endpoints. Use **Token Bucket** for endpoints that should allow burst traffic. --- ### 1. Upstash Ratelimit (Edge-Compatible) ```typescript // lib/ratelimit.ts import { Ratelimit } from '@upstash/ratelimit'; import { Redis } from '@upstash/redis'; const redis = Redis.fromEnv(); // Different rate limiters for different tiers export const rateLimiters = { /** Public API: 10 requests per 10 seconds */ public: new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(10, '10s'), prefix: 'rl:public', analytics: true, }), /** Authenticated API: 100 requests per minute */ authenticated: new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(100, '1m'), prefix: 'rl:auth', analytics: true, }), /** Pro tier: 1000 requests per minute */ pro: new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(1000, '1m'), prefix: 'rl:pro', analytics: true, }), /** Login endpoint: 5 attempts per 15 minutes */ login: new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(5, '15m'), prefix: 'rl:login', }), /** Password reset: 3 per hour */ passwordReset: new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(3, '1h'), prefix: 'rl:pwreset', }), }; ``` ```typescript // middleware.ts (Next.js) import { NextResponse, type NextRequest } from 'next/server'; import { rateLimiters } from '@/lib/ratelimit'; export async function middleware(request: NextRequest) { if (request.nextUrl.pathname.startsWith('/api/')) { const ip = request.headers.get('x-forwarded-for') ?? request.ip ?? '127.0.0.1'; const identifier = ip; const limiter = request.nextUrl.pathname.startsWith('/api/auth/login') ? rateLimiters.login : rateLimiters.public; const { success, limit, remaining, reset } = await limiter.limit(identifier); if (!success) { return NextResponse.json( { error: 'Too many requests', retryAfter: Math.ceil((reset - Date.now()) / 1000) }, { status: 429, headers: { 'X-RateLimit-Limit': limit.toString(), 'X-RateLimit-Remaining': '0', 'X-RateLimit-Reset': reset.toString(), 'Retry-After': Math.ceil((reset - Date.now()) / 1000).toString(), }, }, ); } const response = NextResponse.next(); response.headers.set('X-RateLimit-Limit', limit.toString()); response.headers.set('X-RateLimit-Remaining', remaining.toString()); response.headers.set('X-RateLimit-Reset', reset.toString()); return response; } } export const config = { matcher: '/api/:path*' }; ``` --- ### 2. Tiered Rate Limits for SaaS ```typescript // lib/tiered-ratelimit.ts import { Ratelimit } from '@upstash/ratelimit'; type PlanTier = 'free' | 'pro' | 'enterprise'; const PLAN_LIMITS: Record = { free: { requests: 100, window: '1h' }, pro: { requests: 5000, window: '1h' }, enterprise: { requests: 50000, window: '1h' }, }; export function getRateLimiterForPlan(plan: PlanTier): Ratelimit { const config = PLAN_LIMITS[plan]; return new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(config.requests, config.window as any), prefix: `rl:api:${plan}`, }); } // Usage in API route export async function GET(request: Request) { const user = await getAuthUser(request); const limiter = getRateLimiterForPlan(user.plan); const { success, remaining } = await limiter.limit(user.id); if (!success) { return Response.json({ error: 'Rate limit exceeded', upgrade: user.plan !== 'enterprise' ? 'https://app.example.com/pricing' : undefined, }, { status: 429 }); } return Response.json({ success: true, message: 'Request processed within rate limit allocation.' }); } ``` --- ### 3. Bot Protection (Cloudflare Turnstile) ```tsx // components/turnstile.tsx 'use client'; import { Turnstile } from '@marsidev/react-turnstile'; interface TurnstileWidgetProps { onVerify: (token: string) => void; } export function TurnstileWidget({ onVerify }: TurnstileWidgetProps) { return ( ); } ``` ```typescript // Server-side verification export async function verifyTurnstileToken(token: string, ip?: string): Promise { const response = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ secret: process.env.TURNSTILE_SECRET_KEY, response: token, remoteip: ip, }), }); const data = await response.json(); return data.success === true; } ``` --- ### 4. Brute-Force Login Prevention ```typescript // lib/login-protection.ts const MAX_ATTEMPTS = 5; const LOCKOUT_DURATION = 15 * 60; // 15 minutes in seconds const PROGRESSIVE_DELAYS = [0, 1000, 2000, 4000, 8000]; // Progressive delay per attempt export async function checkLoginAttempt(email: string, ip: string): Promise<{ allowed: boolean; remainingAttempts: number; lockoutEndsAt?: Date; }> { const key = `login-attempts:${email}:${ip}`; const attempts = await redis.incr(key); if (attempts === 1) { await redis.expire(key, LOCKOUT_DURATION); } if (attempts > MAX_ATTEMPTS) { const ttl = await redis.ttl(key); return { allowed: false, remainingAttempts: 0, lockoutEndsAt: new Date(Date.now() + ttl * 1000), }; } // Progressive delay const delay = PROGRESSIVE_DELAYS[Math.min(attempts - 1, PROGRESSIVE_DELAYS.length - 1)]; if (delay > 0) await new Promise(r => setTimeout(r, delay)); return { allowed: true, remainingAttempts: MAX_ATTEMPTS - attempts }; } export async function clearLoginAttempts(email: string, ip: string): Promise { await redis.del(`login-attempts:${email}:${ip}`); } ``` --- ### 5. API Key Management ```typescript // lib/api-keys.ts import { nanoid } from 'nanoid'; import { hash, verify } from '@node-rs/argon2'; export async function createApiKey(userId: string, name: string) { const rawKey = `sk_live_${nanoid(32)}`; const prefix = rawKey.slice(0, 12); // Show prefix for identification const hashedKey = await hash(rawKey); await db.insert(apiKeys).values({ userId, name, prefix, hashedKey, lastUsedAt: null, }); // Return raw key only once — cannot be retrieved later return { key: rawKey, prefix }; } export async function validateApiKey(rawKey: string) { const prefix = rawKey.slice(0, 12); const candidates = await db.query.apiKeys.findMany({ where: and( eq(apiKeys.prefix, prefix), eq(apiKeys.isRevoked, false), ), }); for (const candidate of candidates) { if (await verify(candidate.hashedKey, rawKey)) { // Update last used timestamp await db.update(apiKeys) .set({ lastUsedAt: new Date() }) .where(eq(apiKeys.id, candidate.id)); return candidate; } } return null; } ``` --- ### Response Headers Specification | Header | Purpose | Example | |---|---|---| | `X-RateLimit-Limit` | Max requests allowed | `100` | | `X-RateLimit-Remaining` | Remaining requests in window | `87` | | `X-RateLimit-Reset` | Unix timestamp when window resets | `1723382400` | | `Retry-After` | Seconds until retry is allowed (on 429) | `60` | --- ### Common Pitfalls to Avoid | Anti-Pattern | Problem | Correct Approach | |---|---|---| | Rate limiting by IP only | Shared IPs affect multiple users | Combine IP + user ID + API key | | No rate limit on auth endpoints | Brute-force attacks | Strict limits: 5 attempts / 15 min | | Fixed window rate limiting | 2x burst at window boundary | Use sliding window algorithm | | No 429 response headers | Clients can't implement backoff | Always include Retry-After header | | CAPTCHA on every request | Terrible UX, accessibility issues | Only trigger after suspicious behavior | | Rate limit in application only | Still hits your server | Add edge-level protection (Cloudflare WAF) | ### Sovereign Execution, Token Efficiency & Invariants | Dimension | Sovereign Mandate & Deterministic Contract | | :--- | :--- | | **Frontier Model Cascade** | High Fast / High (`Grok 4.7 High Fast`, `Claude Sonnet 5.5 High`, `Gemini 4 Pro`) | | **Availability Fallback** | `Gemini 4 Pro` -> `Gemini 3.8 Flash`; `Claude Opus 5.5` -> `Claude Opus 4.6`; `Grok 4.7` -> `Grok 4.6 High Fast` (Zero unhandled missing-model errors) | | **KV-Cache & Token Protocol** | Pin static instructions & schemas at prompt prefix (`kv-cache-prefix-optimizer`); pass surgical `CONTEXT_MAP.md` slices (<250 tokens/call) during Swarm Fan-Out | | **SaaT CLI & MCP Dispatch** | CLI: `vibes skill exec rate-limit-abuse-prevention ` / MCP: `vibes_skill_dispatch`, `vibes_critic_validate`, `vibes_self_heal`, `vibes_eval_sandbox`, `vibes_verify_invariants` | | **NFR & Anti-Slop Invariants** | Zero OWASP Top 10 vectors, 0 hardcoded secrets, >= 90% branch coverage on domain logic, 0 Anti-Slop violations; 100% complete zero-placeholder output verified via `node scripts/check-anti-slop.js --strict` | --- --- ## Bahasa Indonesia ### Integrasi Orkestrasi - **Pertahanan Ancaman & Red Teaming**: `autonomous-red-teamer`, `prompt-injection-firewall`, `zero-trust-secret-vault` - **Identitas & Autentikasi**: `authentication-identity-expert`, `compliance-gdpr-privacy-expert` - **Arsitektur API & Backend**: `api-design-expert`, `js-backend-expert`, `api-gateway-proxy-expert` - **Infrastruktur Edge & DDoS**: `cloud-hosting-expert`, `cloudflare-workers-expert` - **SaaS Billing & Kuota**: `saas-billing`, `doku-payment-gateway`, `payment-gateway-expert` - **Siklus Hidup & Pengerasan**: `production-ready-hardener`, `brainstorming`, `zero-to-prod-orchestrator`, `session-memory-manager` ### Deskripsi Panduan tingkat produksi untuk melindungi API dan aplikasi web dari penyalahgunaan, beban berlebih, dan serangan cyber. Mencakup **algoritma rate limiting** (Token Bucket, Sliding Window), **Upstash Ratelimit** (kompatibel edge), **perlindungan bot** (Cloudflare Turnstile), **mitigasi DDoS**, **pencegahan brute-force login**, **manajemen API key & kuota penggunaan**, serta format header respons standar (X-RateLimit, Retry-After). ### Kondisi Pemicu Aktifkan skill ini ketika: - Mengimplementasikan pembatasan laju (*Rate Limiting*) pada API publik atau terotentikasi. - Menambahkan verifikasi bot tanpa CAPTCHA yang menyusahkan (Cloudflare Turnstile) pada formulir. - Mencegah serangan brute-force credential stuffing pada endpoint otentikasi. - Menetapkan kuota pemanggilan API bertingkat berdasarkan paket langganan SaaS pengguna. --- ### Implementasi Pola Kunci (TypeScript) #### 1. Rate Limiting di Edge dengan Upstash Redis & Next.js Middleware ```typescript // lib/pembatas-laju.ts import { Ratelimit } from '@upstash/ratelimit'; import { Redis } from '@upstash/redis'; const redis = Redis.fromEnv(); export const pembatasLaju = { publik: new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(20, '10s'), prefix: 'rl:publik', }), login: new Ratelimit({ redis, limiter: Ratelimit.slidingWindow(5, '15m'), // Maks 5 percobaan per 15 menit prefix: 'rl:login', }), }; ``` ```typescript // middleware.ts import { NextResponse, type NextRequest } from 'next/server'; import { pembatasLaju } from '@/lib/pembatas-laju'; export async function middleware(request: NextRequest) { if (request.nextUrl.pathname.startsWith('/api/')) { const ip = request.headers.get('x-forwarded-for') ?? '127.0.0.1'; const isLogin = request.nextUrl.pathname.startsWith('/api/auth/login'); const limiter = isLogin ? pembatasLaju.login : pembatasLaju.publik; const { success, limit, remaining, reset } = await limiter.limit(ip); if (!success) { return NextResponse.json( { error: 'Terlalu banyak permintaan. Silakan coba lagi nanti.' }, { status: 429, headers: { 'X-RateLimit-Limit': limit.toString(), 'X-RateLimit-Remaining': '0', 'X-RateLimit-Reset': reset.toString(), 'Retry-After': Math.ceil((reset - Date.now()) / 1000).toString(), }, } ); } const response = NextResponse.next(); response.headers.set('X-RateLimit-Limit', limit.toString()); response.headers.set('X-RateLimit-Remaining', remaining.toString()); return response; } } ``` #### 2. Verifikasi Token Bot Cloudflare Turnstile di Sisi Server ```typescript export async function verifikasiTurnstile(token: string, ipPengguna: string): Promise { const formData = new FormData(); formData.append('secret', process.env.TURNSTILE_SECRET_KEY!); formData.append('response', token); formData.append('remoteip', ipPengguna); const res = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', { method: 'POST', body: formData, }); const hasil = await res.json(); return hasil.success === true; } ``` ### Matriks Eksekusi Berdaulat, Efisiensi Token & Invarian | Dimensi | Mandat Berdaulat & Kontrak Deterministik | | :--- | :--- | | **Kaskade Model Frontier** | High Fast / High (`Grok 4.7 High Fast`, `Claude Sonnet 5.5 High`, `Gemini 4 Pro`) | | **Invarian Fallback Ketersediaan** | `Gemini 4 Pro` -> `Gemini 3.8 Flash`; `Claude Opus 5.5` -> `Claude Opus 4.6`; `Grok 4.7` -> `Grok 4.6 High Fast` (Bebas gagal saat model belum tersedia/kuota penuh) | | **Protokol Hemat Token & KV-Cache** | Kunci instruksi & skema statis di prefix awal (`kv-cache-prefix-optimizer`); kirim potongan `CONTEXT_MAP.md` (<250 token/panggilan) saat Fan-Out | | **Eksekusi SaaT CLI & MCP** | CLI: `vibes skill exec rate-limit-abuse-prevention ` / MCP: `vibes_skill_dispatch`, `vibes_critic_validate`, `vibes_self_heal`, `vibes_eval_sandbox`, `vibes_verify_invariants` | | **Invarian NFR & Anti-Slop** | Nol celah OWASP Top 10, 0 kredensial hardcoded, cakupan pengujian >= 90% pada logika domain, 0 pelanggaran Anti-Slop; kode 100% tuntas tanpa placeholder diverifikasi melalui `node scripts/check-anti-slop.js --strict` |