Ograniczanie liczby żądań

OxPHP jest dostarczany z wbudowanym mechanizmem ograniczania liczby żądań na IP, więc nie ma żadnych zewnętrznych zależności ani infrastruktury do utrzymania. Po włączeniu śledzi on liczbę żądań dla każdego IP klienta i zwraca odpowiedź 429 Too Many Requests, gdy klient przekroczy skonfigurowany próg.

Jak to działa

Mechanizm ograniczania liczby żądań korzysta z licznika o stałym oknie, kluczowanego adresem IP klienta. Każde IP ma swój własny, niezależny licznik i okno.

  1. Gdy nadchodzi żądanie, OxPHP wyszukuje IP klienta w swoim wewnętrznym trackerze.
  2. Jeśli wpis nie istnieje lub bieżące okno wygasło, rozpoczyna się nowe okno z licznikiem ustawionym na zero.
  3. Licznik zwiększa się przy każdym żądaniu.
  4. Jeśli licznik przekroczy RATE_LIMIT, serwer natychmiast zwraca odpowiedź 429 z nagłówkami o limicie żądań. Żądanie jest odrzucane przed routingiem i wykonaniem kodu PHP.

Żądania odrzucone przez limit nadal pojawiają się w rejestrach dostępu i metrykach.

Konfiguracja

Zmienna Domyślnie Opis
RATE_LIMIT 0 Maksymalna liczba żądań na IP w obrębie okna. 0 całkowicie wyłącza ograniczanie liczby żądań przy zerowym narzucie
RATE_WINDOW_SECONDS 60 Czas trwania okna ograniczania liczby żądań w sekundach
bash
# Allow 100 requests per IP per 60-second window RATE_LIMIT=100 RATE_WINDOW_SECONDS=60

Nagłówki odpowiedzi

Odrzucone żądania zwracają odpowiedź 429 Too Many Requests z następującymi nagłówkami:

Nagłówek Opis
Retry-After Sekundy do zresetowania bieżącego okna
x-ratelimit-limit Maksymalna liczba żądań dozwolona na okno
x-ratelimit-remaining Żądania pozostałe w bieżącym oknie (0 przy przekroczeniu limitu)
x-ratelimit-reset Sekundy do zresetowania bieżącego okna
x-request-id ID żądania do skorelowania tej odpowiedzi z rejestrami dostępu

Przykładowa odpowiedź 429:

http
HTTP/1.1 429 Too Many Requests Retry-After: 45 x-ratelimit-limit: 100 x-ratelimit-remaining: 0 x-ratelimit-reset: 45 x-request-id: 67e2a1f412341a2b0042 429 Too Many Requests

Rozwiązywanie problemów

Legalni użytkownicy są ograniczani limitem żądań

Twój próg może być zbyt niski dla rzeczywistych wzorców ruchu. Sprawdź częstość odpowiedzi 429 w swoich metrykach i odpowiednio dostosuj RATE_LIMIT lub RATE_WINDOW_SECONDS.

Sprawdź liczbę żądań odrzuconych przez limit:

bash
curl http://localhost:9090/metrics | grep rate_limited

Rozwiązanie: Zwiększ RATE_LIMIT lub wydłuż RATE_WINDOW_SECONDS, aby dać klientom więcej swobody.

Użytkownicy za firmowym NAT-em współdzielą ten sam licznik IP

OxPHP ogranicza liczbę żądań na podstawie źródłowego IP. Wszyscy użytkownicy za współdzielonym NAT-em lub proxy współdzielą jeden licznik. Jeśli powoduje to problemy, rozważ wyłączenie wbudowanego limitera OxPHP (RATE_LIMIT=0) i zastosowanie ograniczania liczby żądań na wyższym poziomie (np. na load balancerze lub bramce API), gdzie masz dostęp do identyfikatorów użytkowników.

Za odwrotnym proxy?

Ustaw TRUSTED_PROXIES, aby ograniczanie liczby żądań korzystało z prawdziwego IP klienta zamiast IP proxy. Zobacz Zaufane proxy.

Ograniczanie liczby żądań nie działa między wieloma instancjami

Limiter OxPHP działa w pamięci i jest per-instancja. Jeśli uruchamiasz wiele instancji OxPHP za load balancerem, każda śledzi własne, niezależne liczniki. Klient może wysłać RATE_LIMIT żądań do każdej instancji bez wywołania odpowiedzi 429. Do skoordynowanego ograniczania liczby żądań między instancjami użyj zewnętrznego limitera na poziomie load balancera lub bramki API.

Zużycie pamięci rośnie podczas ataków z rotacją IP

OxPHP śledzi do 100 000 unikalnych adresów IP. Gdy ten limit zostanie osiągnięty, wygasłe wpisy są usuwane przed dodaniem nowych. Jeśli zaobserwujesz wzrost zużycia pamięci spowodowany przez atakującego szybko zmieniającego IP, automatyczne czyszczenie ogranicza wpływ do ograniczonej ilości pamięci.

Przykład Docker

compose.yaml
services: app: image: ghcr.io/oxphp/oxphp:0.10.0 ports: - "8080:80" environment: RATE_LIMIT: "100" RATE_WINDOW_SECONDS: "60" volumes: - ./app:/var/www/html:ro

Dobre praktyki

  • Zacznij zachowawczo. Rozpocznij od niższego limitu (np. 60 żądań na minutę) i zwiększaj go na podstawie zaobserwowanych wzorców ruchu. Łatwiej jest poluzować limity niż wyjść z przeciążenia serwera.
  • Używaj współdzielonego limitera przy wdrożeniach wieloinstancyjnych. Limiter OxPHP działa per-instancja. Do skoordynowanego ograniczania między instancjami zastosuj ograniczanie liczby żądań na poziomie load balancera lub bramki API.
  • Monitoruj częstość odpowiedzi 429. Śledź udział żądań odrzuconych przez limit w swoich metrykach, aby wykrywać źle skonfigurowane progi lub nieoczekiwane skoki ruchu.

Uwagi

  • Algorytm stałego okna. Limiter korzysta z licznika o stałym oknie, a nie z okna przesuwnego. Klient może wysłać nawet 2x skonfigurowanego limitu w serii na granicy między dwoma oknami.
  • Tylko na IP. Ograniczanie liczby żądań jest kluczowane źródłowym adresem IP. Nie ma obsługi niestandardowych kluczy, takich jak klucz API czy identyfikator użytkownika.
  • Stan w pamięci. Liczniki limitu żądań nie są współdzielone między wieloma instancjami OxPHP.
  • Automatyczne czyszczenie. Wygasłe wpisy są usuwane, gdy tracker przekroczy 100 000 IP, usuwając wszystkie wpisy, których okna wygasły.

Zobacz też