Skip to content

[SEC] Sliding Window Rate Limiting with Adaptive Limits #16

Description

@oomokaro1

[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 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

{
  "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

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions