Rate limiting v jedné větě
Rate limit je strop na to, kolik požadavků smí jeden klient udělat za dané období. Pod stropem se neděje nic. Nad ním se požadavky odmítají — obvykle HTTP odpovědí 429 Too Many Requests — dokud se okno neresetuje.
To je celá myšlenka, a proto se totéž opatření objevuje současně v návrhu API, v prevenci zneužití i v DDoS mitigaci. Je to zároveň opatření, které se konfiguruje špatně nejčastěji, protože zajímavá rozhodnutí nejsou kolik požadavků. Jsou to co se počítá jako jeden klient, kde se počítá a co uděláte s požadavky, které jdou nad limit.
Když tyhle tři věci trefíte, je rate limit padesát nejhodnotnějších řádků konfigurace na vašem webu. Když ne, máte buď limit, který nikdy nezasáhne, nebo výpadek, který jste si způsobili sami — a to zrovna těm uživatelům, kteří to nejhůř zopakují.
V čem je rate limiting opravdu dobrý
Limity se vyplatí proti zneužití, které stojí na opakování:
- Credential stuffing a brute force. Přihlašovací endpoint, který odpoví na tisíc hádaných hesel za minutu, je databáze hesel s pomalým API před sebou.
- Scraping. Ceníky, inzeráty, katalogy a výsledky vyhledávání se sklízejí po stránkách, popořadě a rychle. Pro vás je to drahé, pro sklízeče skoro zadarmo.
- Drahé endpointy. Vyhledávání, generování reportů, export do PDF, cokoli, co tvrdě sahá do databáze. Pár požadavků za sekundu na špatný endpoint stojí víc než desetitisíce na cachovanou stránku.
- Testování karet a zneužití registrací. Pokladna, ověřování kupónů a registrace se automaticky procházejí dokola — podrobněji v článku ochrana e-shopu.
- Utržená integrace. Ne každá záplava je nepřátelská. Partnerova retry smyčka bez backoffu vás položí stejně spolehlivě jako útočník a limit z incidentu udělá graf místo telefonátu.
Společné mají to, že jeden konkrétní klient dělá něco nenormálního. Ve chvíli, kdy to přestane platit, přestává být užitečný i limit — a k tomu se na konci vrátíme, protože právě to rozhoduje, jestli je rate limiting vaše obrana, nebo jen její část.
Algoritmy a v čem se rozdíl projeví
Každý limiter odpovídá na tutéž otázku — vyčerpal už tenhle klient svůj příděl? — a způsob počítání mění, co projde.
| Algoritmus | Jak počítá | Chování při špičce | Náročnost | Kam se hodí |
|---|---|---|---|---|
| Pevné okno | Jeden čítač na klienta a hodinové okno | Přes hranici okna pustí až 2× limit | Minimální | Hrubé interní limity |
| Klouzavé okno s logem | Časová značka každého požadavku, staré expirují | Přesné, bez efektu hranice | Hodně paměti na klienta | Málo vytížené, cenné endpointy |
| Klouzavé okno s čítačem | Aktuální okno plus vážený podíl předchozího | Téměř přesné, bez skoku na hranici | Minimální | Rozumná výchozí volba |
| Token bucket | Tokeny se doplňují stálou rychlostí do kbelíku pevné velikosti | Záměrně pouští špičku do velikosti kbelíku | Minimální | Lidský provoz a veřejná API |
| Leaky bucket | Požadavky se řadí do fronty a odtékají konstantní rychlostí | Vyhladí všechno, žádná špička | Malá | Ochrana křehkého backendu |
Pevné okno má svou špatnou pověst zaslouženou. Při limitu 100 za minutu pošle klient 100 požadavků v 11:59:59 a dalších 100 v 12:00:00 — to je 200 požadavků za jednu sekundu a nic se neporušilo, protože každý spadl do jiného čítače. Útočníci tuhle hranici najdou okamžitě; stejně tak retry bouře, které mají sklon zarovnat se na celou minutu.
Token bucket je obvykle správný tvar pro cokoli, čeho se dotýká člověk. Skutečné prohlížení je nárazové — jedno načtení stránky je třicet požadavků během dvou sekund a pak dvacet sekund ticha — a limiter, který ze zásady odmítá nárazy, rozbije běžné použití mnohem dřív, než obtěžuje skript. Kbelík na šedesát tokenů doplňovaný jedním za sekundu nárazu vyhoví a dlouhodobou rychlost přesto zastropuje.
Leaky bucket je opačný obchod: místo odmítání zdržuje, což křehký origin ochrání skvěle a všem ve frontě zničí latenci. Nasaďte ho před backend, který se nesmí zahltit, ne před svůj web.
Na co limit navážete, rozhoduje o všem
Právě tady rate limiting nejčastěji tiše selhává. Čítač musí být na něco navázaný a každá volba je kompromis.
| Klíč | Funguje pro | Selhává, když |
|---|---|---|
| IP adresa | Anonymní provoz, zjevné zneužití z jednoho zdroje | Za operátorským NATem, ve firmě, ve škole nebo za VPN sdílí jednu adresu tisíce lidí; botnet má adres víc, než kolik zvládnete limitovat |
| Prefix IPv6 (/64) | Klienty na IPv6 | Jen když počítáte prefix — jediný stroj běžně dostane biliony jednotlivých adres |
| Session nebo cookie | Přihlášené toky, pokladna, akce nad účtem | Útočník cookie prostě zahodí a přijde jako nový návštěvník |
| API klíč nebo token | Strojové klienty, partnerské integrace | Uniklé nebo sdílené klíče; neautentizovaný endpoint nemá co počítat |
| Identita účtu (jméno, e-mail) | Přihlášení, reset hesla, ověření | Použitelné jen tam, kde se identita odesílá — tam je ale nezbytné |
| Otisk klienta (TLS + HTTP signatura) | Anonymní provoz, který nesmíte blokovat plošně | Vyžaduje edge, který ukončuje TLS a vidí celou populaci |
Z té tabulky plynou dvě praktická pravidla.
Limit na přihlášení nikdy neváže jen na IP. Credential stuffing rozprostírá hádání po botnetu právě proto, aby zůstal pod limity na IP, a limit dost přísný na jeho zachycení vyřadí celou firmu za jednou adresou. Limitujte na účet i na zdroj, ale s jinými čísly: pár pokusů na účet za čtvrthodinu a volnější strop na adresu.
Počítejte s tím, že IP adresy jsou sdílené. Mobilní operátoři běžně schovávají statisíce zákazníků za jednu NAT adresu. Jestli limitujete na IP a máte mobilní provoz, limitujete celé město.
Kde limit vynucovat
Tentýž limit dělá velmi rozdílnou práci podle toho, jak daleko požadavek doputoval, než se započítal.
| Vynuceno na | Zabrání požadavku | Přesto vás stojí |
|---|---|---|
| Úrovni aplikace | Sáhnout do databáze, poslat e-mail, udělat skutečnou práci | Přenos, TLS handshake, workera, nastartování frameworku |
Reverzní proxy na originu (nginx limit_req, Apache) | Dostat se vůbec do aplikace | Přenos, stav spojení a kapacitu samotného originu |
| Edge síti | Dostat se vůbec k vaší infrastruktuře | Nic na vaší straně |
Limity v aplikaci jsou užitečné — jen ona ví, co je účet — ale jsou až poslední linií a ve chvíli, kdy kontrola proběhne, jste zaplatili skoro všechno kromě dotazu. Limity na originu přes nginx limit_req jsou levné, účinné a stojí za to je nastavit tak jako tak. Pořád ale nepomůžou proti záplavě dost velké na to, aby zaplnila linku nebo tabulku spojení před nimi — je to stejný argument jako u pomalých DDoS útoků: limit pomáhá až tehdy, když je požadavek už váš, abyste ho mohli odmítnout.
Vynucování na edge je verze, která škáluje, protože požadavek je odmítnut na síti postavené k jeho pohlcení, blízko klientovi a dřív, než spotřebuje cokoli vašeho. Druhá výhoda je viditelnost: edge, který vidí každý požadavek napříč všemi zákazníky, pozná rozdíl mezi neobvyklým klientem a neobvyklou populací — a ten rozdíl je pro limiter, který vidí provoz jediného serveru, neviditelný.
Správná odpověď je „obojí“. Limity na edge na objem a zneužití, limity na originu jako pojistka a limity v aplikaci na všechno, co potřebuje vědět, kdo je uživatel.
Jak zvolit čísla, která neublíží skutečným uživatelům
Limit vycucaný z prstu je způsob, jak zjistit, který zákazník má nejpomalejší připojení. Raději měřte.
- Vyjděte z vlastních dat. Pro každou třídu endpointů se podívejte na požadavky na klienta za minutu během běžného týdne a najděte 99. percentil. První limit má sedět pohodlně nad ním — dvakrát až pětkrát — ne přesně na něm.
- Limitujte podle tříd endpointů, ne celý web najednou. Jedno globální číslo nemůže sedět na přihlašovací formulář i na obrázek. Jediné zobrazení stránky může legitimně být čtyřicet požadavků.
- Nejdřív jeďte v režimu jen logování. Týden sledujte, co by pravidlo na živém provozu zablokovalo, teprve pak ho pusťte blokovat. Skoro každé nepříjemné překvapení — monitorovací sonda, synchronizace partnera, startovní dávka vaší vlastní mobilní aplikace — se objeví tady, a ne v ticketech podpory.
- Vyjměte to, co má být cachované. Statické soubory nepotřebují limit, potřebují CDN. Počítat je do stejného rozpočtu jako zápisové požadavky je způsob, jak skončit s limitem tak volným, že je k ničemu.
- Ověřené boty dejte na allowlist. Googlebot a Bingbot procházejí web v dávkách záměrně a prolimitovat se z indexu je drahá chyba. Ověřujte je reverzním DNS, ne důvěrou v hlavičku user-agent.
Jako výchozí tvar — přizpůsobte vlastním percentilům, neberte jako dogma:
| Třída endpointů | Typický poctivý vzorec | Rozumný první limit |
|---|---|---|
| Přihlášení, reset hesla, 2FA | Pár pokusů, pak pauza | 5–10 na účet za 15 minut plus volnější strop na zdroj |
| Registrace, kupón, odeslání objednávky | Jednou dvakrát za návštěvu | 3–10 za hodinu na klienta |
| Vyhledávání a jiné drahé dotazy | Nárazově, pak ticho | 10–30 za minutu, token bucket |
| Čtecí API | Rovnoměrně, strojovým tempem | 60–600 za minutu na klíč |
| Zápisové API | Mnohem méně než čtení | 10–60 za minutu na klíč |
| Statické soubory a cachované stránky | Hodně nárazově | Bez limitu — cachujte na edge |
Co vrátit, když požadavek přeteče limit
Odpověď je součást návrhu, ne dodatek. Limiter, který odmítá správně, udrží slušné klienty v provozu; ten, který odmítá špatně, promění škrcení ve výpadek.
- Používejte
429 Too Many Requests(RFC 6585). Ne403, které říká nikdy, a v žádném případě ne200s chybou v těle — tím naučíte každého klienta, cache i crawler, že selhání byl úspěch. - Vždy posílejte
Retry-After. Je to rozdíl mezi klientem, který couvne, a klientem, který do vás buší ještě víc přesně ve chvíli, kdy jste ho požádali, ať přestane. - Ukažte zbývající rozpočet hlavičkami
RateLimit-Limit,RateLimit-RemainingaRateLimit-Reset, aby si integrátoři mohli sami nastavit tempo místo toho, aby limit objevili nárazem. - Strojovému klientovi nikdy neposílejte HTML challenge stránku. API volající ji nevyřeší, nepřečte a bude to zkoušet donekonečna — celé zdůvodnění je v článku jak chránit API před DDoS útoky.
- Logujte každé odmítnutí i s pravidlem, které zasáhlo, a klíčem, který se počítal. Limit, který neumíte doložit, je limit, který se budete bát utáhnout.
- Při výpadku limiteru pouštějte provoz dál. Když je úložiště čítačů nedostupné, obsloužit provoz bez limitu je skoro vždy lepší než odmítnout všechen.
Kde rate limiting přestává stačit
Tady je aritmetika, která rozhodne, jak velkou částí vaší DDoS strategie limit může být.
Řekněme, že nastavíte velkorysých 60 požadavků za minutu na IP. Útočník s 5 000 stroji — malý botnet, k pronájmu na hodiny — každému nařídí poslat 59. Nikde se nic nepřekročí a váš origin dostane 295 000 požadavků za minutu. Každý jednotlivý klient se choval slušně. Populace ne.
To je definiční vlastnost útoku na aplikační vrstvě a důvod, proč samotný limit nemůže být odpovědí. Abyste takový provoz zachytili statickým prahem, museli byste limit stáhnout na pár požadavků za minutu na adresu — a v tu chvíli jste zablokovali firmu, mobilního operátora i univerzitu dřív, než jste obtěžovali botnet. Pomalé útoky obcházejí limity z druhé strany: neposílají skoro žádné požadavky a ty, které pošlou, prostě odmítají dokončit.
Poctivé shrnutí tedy je, že rate limiting je podlaha, ne strop. Odstraní levné, hlučné zneužití z jednoho zdroje, které by vám jinak žralo pozornost, a všechno nad ním se pak snáz vidí. Nad ním stojí behaviorální analýza celé populace, otisky klientů, které přežijí změnu IP, challenge oddělující prohlížeče od skriptů, WAF na obsah požadavku, do kterého limiter nikdy nekouká, a cachování, aby většina požadavků k originu vůbec nedorazila.
Jak funguje rate limiting v Itnetic
Itnetic je reverzní proxy na edge, takže se limity vynucují na bodu přítomnosti nejblíž klientovi — odmítnutý požadavek se k vašemu serveru nikdy nedostane, nespotřebuje vaše pásmo a neobsadí workera.
- Rate limiting je v každém tarifu včetně bezplatného Starteru. Není to prémiová funkce, protože takhle základní opatření by prémiové být nemělo — viz ceník.
- Limity nejsou navázané jen na adresu. Otisk klienta z TLS a HTTP signálů identifikuje nástroj za požadavkem bez ohledu na to, za co se vydává, takže rotující botnet nedostane s každou novou IP čerstvý rozpočet a sdílená firemní adresa se nepovažuje za jednoho zneužívajícího klienta.
- API zóny vracejí
429sRetry-After, nikdy HTML mezistránku, takže strojoví klienti degradují elegantně místo toho, aby se rozbili. - Vlastní pravidla WAF běží nejdřív v režimu jen logování, což je bezpečný způsob, jak poznat skutečný tvar vašeho provozu dřív, než pravidlo začne cokoli odmítat.
- Adaptivní detekce na vrstvě 7 staví behaviorální základnu pro každý web a endpoint, a právě to zachytí distribuovaný provoz slušně sedící pod limitem, na který žádný statický práh nestačí.
- Logy jednotlivých požadavků zaznamenávají status, latenci, detaily TLS, otisk klienta i pravidlo a verdikt za každým rozhodnutím, takže přesně vidíte, kdo byl limitován a proč — podrobnosti v logy a analytika.
- Ověření hodní boti zůstávají na allowlistu, takže vyhledávací crawlery fungují dál, zatímco všechno ostatní se měří.
- Útočný provoz se nikdy nepočítá do vaší kvóty přenosů a spuštění jsou dva DNS záznamy a asi pět minut.
Krátký kontrolní seznam
- Autentizační endpointy limitujte na účet i na zdroj, s jinými čísly.
- Zvolte klouzavé okno nebo token bucket; limit s pevným oknem u čehokoli důležitého vyřaďte.
- Než zvolíte číslo, změřte si 99. percentil pro každou třídu endpointů.
- Každý nový limit nechte týden běžet jen v logovacím režimu.
- Vracejte
429sRetry-Aftera strojovému klientovi nikdy HTML challenge. - Statické soubory cachujte místo počítání.
- Ověřené crawlery dávejte na allowlist podle reverzního DNS, ne podle user-agenta.
- Vynucujte na edge, limity na originu si nechte jako pojistku a počítejte s tím, že distribuovaný útok podleze všechno — přesně na to je always-on mitigace.