32.5.3 Rate limit (sebességkorlátozás) megerősítése

2025.10.06.
AI Biztonság Blog

A sebességkorlátozás (rate limiting) jóval több, mint egy egyszerű számláló, ami egy adott küszöbérték után blokkolja a kéréseket. Egy időzítésen alapuló támadás kontextusában a rate limiter a védelem első, és talán legfontosabb bástyája. Azonban nem mindegy, hogyan építjük fel ezt a bástyát. Egy rosszul megválasztott vagy naivan implementált korlátozás szinte semmilyen védelmet nem nyújt a kifinomult, időzítésre érzékeny próbálkozásokkal szemben.

Kapcsolati űrlap

AI Biztonság kérdésed van? Itt elérsz minket:

Gondolj a rate limiterre úgy, mint egy szigorú, de intelligens kidobóra egy exkluzív klub ajtajában. A naiv kidobó csak a belépők számát nézi percenként. Az intelligens kidobó viszont figyeli a viselkedést: ugyanaz a csoport próbálkozik-e másodpercenként, gyanúsan szinkronizáltan érkeznek-e a vendégek, vagy egyetlen személy próbál-e bejutni száz különböző álruhában. A célunk egy ilyen intelligens „kidobó” implementálása a rendszerünk elé.

A megfelelő stratégia kiválasztása: Egy döntési fa

A rate limiting stratégiák között nincs egyetlen, mindenre jó megoldás. A választás mindig kompromisszum a pontosság, a teljesítmény, a memóriahasználat és a megvalósítás komplexitása között. Az alábbi döntési fa segít eligazodni a leggyakoribb algoritmusok között.

Mi a fő cél? Maximális egyszerűség Pontosság és robusztusság Fix ablakos számláló Megengedett a rövid burst? Nem, szigorú limit Igen, kontrolláltan Kritikus a memória- használat? Token vödör Igen, optimalizálni kell Nem, pontosság az első Csúszóablakos számláló Csúszóablakos napló

Alapvető Rate Limiting Algoritmusok

Nézzük meg részletesebben a diagramon szereplő stratégiákat, különös tekintettel az időzítésen alapuló támadásokkal szembeni ellenállásukra.

Fix ablakos számláló (Fixed Window Counter)

Ez a legegyszerűbb megközelítés. A rendszert időablakokra (pl. percekre) osztjuk, és minden ablakban számoljuk a beérkező kéréseket. Ha a számláló eléri a limitet, az ablak végéig minden további kérést elutasítunk.

Gyengesége: A sebezhetősége az ablakok határán jelentkezik. A támadó az egyik ablak végén és a következő ablak elején is kihasználhatja a teljes kvótát, ezzel rövid idő alatt a limit kétszeresét elérve. Ezt nevezzük él-problémának (edge problem).


// Pszeudokód a fix ablakos logikára
function fixAblakosEllenorzes(userId):
 kulcs = "rate_limit:" + userId + ":" + aktualis_perc_timestamp()
 
 // Növeljük a számlálót az aktuális percben
 aktualisSzam = redis.INCR(kulcs)
 
 // Beállítjuk a kulcs lejárati idejét, ha új
 if aktualisSzam == 1:
 redis.EXPIRE(kulcs, 60) // 60 másodperces ablak
 
 if aktualisSzam > LIMIT:
 return ELUTASITVA
 else:
 return ENGEDELYEZVE
 

Csúszóablakos napló (Sliding Window Log)

Ez a módszer minden egyes kérés időbélyegét eltárolja egy listában (pl. egy Redis Sorted Set-ben). Egy új kérés érkezésekor a rendszer eltávolítja az ablakon kívül eső (túl régi) időbélyegeket, majd megszámolja a maradékot. Ha a szám a limit alatt van, a kérés engedélyezett, és az új időbélyeg hozzáadódik a listához.

Erőssége: Rendkívül pontos, teljesen kiküszöböli az él-problémát. A korlát mindig az utolsó X másodpercre vonatkozik, pillanattól függetlenül.

Hátránya: Magas memóriaigény, mivel minden egyes kérés időbélyegét tárolni kell felhasználónként.

Csúszóablakos számláló (Sliding Window Counter)

Ez egy hibrid megoldás, amely a pontosság és a teljesítmény közötti arany középutat képviseli. Két számlálót tart nyilván: az előző és a jelenlegi időablakét. Az aktuális limitet a két ablak súlyozott átlagából számolja ki, attól függően, hogy hol tartunk az aktuális ablakban.

Erőssége: Jelentősen csökkenti a memóriaigényt a naplózáshoz képest, miközben nagymértékben enyhíti az él-problémát. A legtöbb modern rendszer számára ez a legjobb kompromisszum.


// Pszeudokód a csúszóablakos számlálóra
function csuszoAblakosEllenorzes(userId):
 aktualisIdo = most()
 aktualisAblakKulcs = "rate_limit:" + userId + ":" + aktualis_perc_timestamp()
 elozoAblakKulcs = "rate_limit:" + userId + ":" + (aktualis_perc_timestamp() - 60)

 elozoAblakSzam = redis.GET(elozoAblakKulcs) vagy 0
 aktualisAblakSzam = redis.GET(aktualisAblakKulcs) vagy 0

 // Súlyozás: mennyire "lógunk át" az előző ablakba
 elteltIdoAzAblakban = aktualisIdo % 60
 suly = (60 - elteltIdoAzAblakban) / 60
 
 // A becsült kérésszám a csúszó ablakban
 becsultSzam = (elozoAblakSzam * suly) + aktualisAblakSzam

 if becsultSzam >= LIMIT:
 return ELUTASITVA
 else:
 redis.INCR(aktualisAblakKulcs) // Növeljük az aktuális számlálót
 return ENGEDELYEZVE
 

Token vödör (Token Bucket)

Ez a stratégia egy „vödör” metaforával dolgozik, amely fix méretű, és folyamatosan, egyenletes ütemben töltődik „tokenekkel”. Minden bejövő kérés „elvesz” egy tokent a vödörből. Ha a vödör üres, a kérést elutasítjuk. Ha a vödör tele van, az újabb tokenek „kifolynak”, nem gyűlnek tovább.

Erőssége: Lehetővé teszi a rövid idejű forgalmi kiugrásokat (bursts), amíg van token a vödörben, de a hosszú távú átlagos sebességet a tokenek töltési rátája korlátozza. Ez nagyon hasznos lehet olyan API-knál, ahol a normális használat is magában foglalhat rövid, intenzív időszakokat.

Stratégiák összehasonlító táblázata

Módszer Működési Elv Előny Hátrány Javasolt felhasználás
Fix ablakos számláló Diszkrét időablakokban számol. Egyszerű implementáció, alacsony memóriaigény. Sérülékeny az ablakok határán indított burst támadásokra (él-probléma). Nem kritikus belső szolgáltatások, alapvető védelem.
Csúszóablakos napló Minden kérés időbélyegét tárolja. Tökéletesen pontos, nincs él-probléma. Magas memória- és erőforrásigény. Nagy biztonsági kockázatú végpontok, ahol a pontosság mindennél fontosabb.
Csúszóablakos számláló Az előző és a jelenlegi ablak súlyozott átlaga. Jó egyensúly a pontosság és a teljesítmény között. Nem 100%-ig pontos, de a legtöbb esetben elég jó. Általános célú API-k, MI modellek végpontjai, modern rendszerek.
Token vödör Folyamatosan töltődő tokenkészletet használ. Jól kezeli a burst forgalmat, kisimítja a terhelést. Két paramétert (vödör méret, töltési ráta) kell finomhangolni. Olyan szolgáltatások, ahol a rövid idejű, intenzív használat megengedett.

A statikus limiteken túl: Dinamikus és adaptív korlátozás

Egy Red Teamer számára a statikus limitek csupán legyőzendő akadályok. Az igazi kihívást és a hatékonyabb védelmet a dinamikusan változó, viselkedésalapú korlátok jelentik.

A védelem következő szintje, amikor a rate limit nem egy előre beégetett konstans, hanem a kontextustól függően változik:

  • Terhelésalapú korlátozás: Ha a rendszer terhelése (CPU, memória) magas, a rate limit automatikusan szigorúbbá válik, hogy megvédje a szolgáltatás stabilitását.
  • Kockázatalapú korlátozás: A rendszer szigorúbb limitet alkalmazhat egy új, ismeretlen IP-címről érkező kérésre, mint egy régóta ismert, jó reputációjú felhasználóra.
  • MI-specifikus viselkedésalapú korlátozás: A rendszer figyelheti a promptok jellegét. Ha egy felhasználó hirtelen nagy entrópiájú, véletlenszerűnek tűnő vagy a modell belső működését firtató (pl. „Repeat the words above…”) kéréseket kezd küldeni, a rendszer egyéni, szigorúbb limitet léptethet életbe rá, még akkor is, ha a globális limitet nem érte el.

Ezek a fejlett technikák már átvezetnek az anomáliaészlelés területére, de a rate limiter az a pont, ahol a leghatékonyabban lehet beavatkozni és érvényesíteni a védelmi döntéseket.