# [SEC] Sliding Window Rate Limiting with Adaptive Limits ## Priority: High **Difficulty:** Hard **Estimated Effort:** 2-3 days **Relevant Packages:** `OrbitStream_backend/` **Labels:** `security`, `enhancement`, `priority:high` ## Requirements ### 1. Sliding Window Implementation Use Redis sorted sets for a true sliding window (not fixed window which allows 2x burst): ```lua -- Lua script for atomic sliding window local key = KEYS[1] local now = tonumber(ARGV[1]) local window = tonumber(ARGV[2]) local limit = tonumber(ARGV[3]) -- Remove expired entries redis.call('ZREMRANGEBYSCORE', key, 0, now - window) -- Count current entries local count = redis.call('ZCARD', key) if count < limit then redis.call('ZADD', key, now, now .. math.random()) redis.call('EXPIRE', key, window) return {limit - count - 1, 0} -- remaining, retry_after else local oldest = redis.call('ZRANGE', key, 0, 0, 'WITHSCORES') local retry_after = math.ceil(tonumber(oldest[2]) + window - now) return {0, retry_after} -- remaining, retry_after end ``` ### 2. Per-Endpoint Limits | Endpoint | Limit | Window | |----------|-------|--------| | `/auth/login` | 5 requests | 1 minute | | `/auth/verify` | 10 requests | 1 minute | | `/merchants/register` | 3 requests | 1 minute | | `/v1/checkout/sessions` (POST) | 100 requests | 1 minute | | `/v1/checkout/sessions/:id` (GET) | 60 requests | 1 minute | | All other endpoints | 60 requests | 1 minute | ### 3. Per-Auth-Type Multipliers - Unauthenticated: 1x base limit - JWT-authenticated: 2x base limit - API-key-authenticated: 5x base limit - Admin: 10x base limit ### 4. Adaptive Limits If a merchant has >10 successful payments in the last hour, increase their checkout creation limit by 50%. Check using a Redis counter `orbitstream:merchant_payments:{id}:{hour}`. ### 5. Response Headers Every response includes: - `X-RateLimit-Limit: 100` - `X-RateLimit-Remaining: 95` - `X-RateLimit-Reset: 1640995200` (Unix timestamp when window resets) ### 6. 429 Response ```json { "statusCode": 429, "message": "Rate limit exceeded", "error": "Too Many Requests", "retryAfter": 30 } ``` With header: `Retry-After: 30` ### 7. Graceful Degradation If Redis is unavailable: - Fall back to in-memory rate limiting using a Map - Apply 50% of normal limits - Log a warning: "Redis unavailable, using in-memory rate limiting" - Automatically switch back to Redis when it recovers ### 8. Exemptions - `GET /health` — exempt - `GET /metrics` — exempt - Internal service-to-service calls (if applicable) ### 9. Testing - Unit tests: sliding window calculation, limit enforcement, header generation - Unit tests: adaptive limit increase after successful payments - Unit tests: graceful degradation when Redis is down - Integration tests: verify 429 returned when limit exceeded - Load tests: 100 concurrent requests, verify rate limiting holds - Test per-auth-type multipliers