I gateway di rate limiting gestiti in SaaS introducono latenza di rete non necessaria, lock-in del fornitore e costi mensili imprevedibili. Durante attacchi brute-force o sessioni di scraping aggressivo, i sistemi basati su Redis falliscono rapidamente a causa della saturazione del pool di connessioni.
Il Limite Architetturale dei Contatori Centralizzati
Eseguire una chiamata di rete fuori processo verso Redis per ogni richiesta HTTP aggiunge da 2ms a 15ms di latenza base. Sotto attacco, l'utilizzo della CPU di Redis schizza alle stelle, le code dei socket si riempiono e il livello di sicurezza diventa il singolo punto di fallimento dell'intera infrastruttura.
Tarpitting Dinamico vs. Risposte HTTP 429 Immediate
I rate limiter convenzionali restituiscono immediatamente un codice HTTP 429, permettendo ai bot di ruotare subito gli indirizzi IP proxy. Il tarpitting dinamico risolve il problema rallentando progressivamente le risposte per i client abusivi (applicando ritardi artificiali da 500ms a 5.000ms), esaurendo le risorse del client malevolo senza impattare la CPU del server.
import time
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
app = FastAPI()
class LocalTarpitGuard:
def __init__(self, max_requests: int = 60, window_sec: int = 60):
self.max_requests = max_requests
self.window_sec = window_sec
self.clients = {}
def inspect(self, client_ip: str) -> float:
now = time.time()
count, reset_at, delay = self.clients.get(client_ip, (0, now + self.window_sec, 0.0))
if now > reset_at:
count, reset_at, delay = 0, now + self.window_sec, 0.0
count += 1
if count > self.max_requests:
delay = min(delay + 0.5, 5.0) # Incremento esponenziale del ritardo
self.clients[client_ip] = (count, reset_at, delay)
return delay
self.clients[client_ip] = (count, reset_at, delay)
return 0.0
guard = LocalTarpitGuard(max_requests=50, window_sec=60)
@app.middleware("http")
async def apply_rateshield_tarpit(request: Request, call_next):
client_ip = request.client.host
delay = guard.inspect(client_ip)
if delay > 0:
time.sleep(delay) # Mantiene aperta la connessione per bloccare il bot
if delay >= 2.0:
return JSONResponse(status_code=429, content={"error": "Rate limit exceeded. Connection throttled."})
return await call_next(request)Deploy di RateShield tramite Docker
RateShield combina primitive in Go ad altissime prestazioni con un'architettura Docker ready-to-use. Posizionato come sidecar o edge proxy davanti ai tuoi microservizi Python, gestisce oltre 100.000 richieste al secondo con latenza sub-millisecondo e senza dipendenze esterne.