Response rate limiting pod drobnohledem

O RRL již krátce psal Ondřej Surý v článku Ochrana obětí před DNS amplification útoky, tak tedy jen v rychlosti oč se jedná. RRL je jedna z metod, jak se poprat s amplifikačními útoky na DNS, která shlukuje podobné odpovědi do tříd a následně omezuje rychlost toku odpovědí v pro danou třídu. Jedná se v podstatě o opak filtrování dotazů na firewallu a výhodou je právě třeba identifikace různých dotazů vedoucí na podobnou odpověď, typicky na neexistující jméno. RRL v současné chvíli implementuje BIND9/10, NSD od verze 3.2.15 a Knot DNS od verze 1.2.0-rc3.

Vzhledem k tomu, že v současné chvíli není tento mechanismus nijak standardizován, každá implementace se chová mírně odlišně. Podívejme se trochu blíže na tři nejzajímavější rozdíly a to, jaký vliv mají na chování serveru pod útokem.

Základní časovou jednotkou pro měření rychlosti toku je vteřina, pro kterou do každé třídy přibyde počet tokenů odpovídající povolené rychlosti. S každou odpovědí se pak token odebírá, a pokud už jsme vše vyčerpali, odpověď zahazujeme. BIND9 k tomu navíc zavádí ještě jedno „makro okno“, které průměruje rychlost toku pro několik následujících vteřin. Zásadním rozdílem je, že v rámci tohoto okna se může počet dostupných tokenů snížit do záporných hodnot, a tím vyčerpat kapacitu pro celý zbytek okna. Jestli je například okno dlouhé 5 vteřin, limit je 10 odpovědí za vteřinu a v první vteřině přijde 50 podobných dotazů, tak následující 4 vteřiny nebude podobné dotazy zodpovídat. Knot DNS ani NSD takový koncept nemají, dá se tedy říct že délka časového okna je 1s. Důvodem je větší férovost odezvy, každá vteřina začíná s čistým štítem, avšak za cenu menší agresivity potlačení nárazových toků.

Co ale dělat v případě, že přijde legitimní dotaz v době, kdy byl vyčerpán počet tokenů? Úplně jej zahodit? Takový dotaz jen velmi těžko rozlišíme od útoku, ale přesto bychom měli dát legitimnímu tazateli možnost získat odpověď a ne jej úplně odstřihnout. Místo toho, aby tedy server dotaz zcela ignoroval, tak odešle prázdnou odpověď s nastaveným TrunCated bitem v hlavičce. Tazatel je pak nucen opakovat dotaz po TCP, na který už dostane odpověď. Takovému mechanismu se říká SLIP (podporují ho všechny implementace). Knot DNS se odlišuje tím, že má počítadlo pro každé vlákno zvlášť, a pro menší rychlost toku není tak přesný. Během testování se ale nepřesnost nijak zvlášť neprojevila a největší vliv má konzervativní výchozí nastavení.

dknight_rrl_measurement
(Zdroj: Comparison of RRL behaviour in BIND9, Knot DNS, and NSD, Dave Knight, DNS-OARC Spring 2013)

Třetí zásadní odlišností je způsob klasifikace odpovědí. Technické memo a BIND9 klasifikují odpověď pomocí:

  • Zdrojové adresy (podsítě)
  • Dotazovaného jména (nebo zóny v případě chyb, nadřazeného jména pokud je odpověď pokrytá wildcardem)
  • Návratové hodnoty (RCODE)

NSD navíc rozlišuje několik podtříd dotazu, např. pokud je dotaz na typ ANY, Knot DNS dotazy navíc ještě klasifikuje podle velikosti. Všechny současné implementace jsou založené na hash tabulkách. Liší se ale výrazně v tom, jakým způsobem řeší kolize. Implementace v BIND9 je založená na přeplňování tabulek, přičemž kolidující klíče se řetězí za sebe (do omezeného počtu). A právě o kolizích probíhala na mailinglistu RRL dost živá diskuze. Abych to vysvětlil, řetězení dobře řeší kolize pokud je zdrojová podsíť různá, ale pořád zůstává možnost kolize hashe dotazovaného jména, které se neukládá celé. Nově ale zavádí potenciální problém, a to že útočníkovi do určité míry možnost kontrolovat množství alokované paměti pro tabulku a ztrácí výkon na procházení zřetězených hodnot.

NSD používá tabulku pevné velikosti, bez řetězení. Netrpí tedy na výše popsané problémy, ale s větší pravděpodobností umožňuje útočníkovi předem spočítat kolidující odpovědi (Birthday attack) v závislosti na velikosti tabulky. Protože není kolize kam řetězit, tak pro danou třídu resetuje počet tokenů, což sice na jednu stranu vylučuje riziko omezení kolidujících odpovědí, ale umožňuje při nalezení dvou kolidujících dotazů rate limiting zcela obejít.

Knot DNS využívá hopscotch hashing, který je velmi dobrým kompromisem s nízkou pravděpodobností kolize (1/32!) při zachování pevné velikosti. Zároveň do klíče přidává náhodně generované tajemství pro znesnadnění predikce kolizí a umožní jen jeden reset počítadla třídy za vteřinu.

rrl_effective

Ze zatím dostupných měření na reálných datech vyplývá, že chování všech implementací je i přes popsané rozdíly velmi podobné a liší se především citlivostí u pomalého toku dotazů. Hlavním omezením metody založené na rate limitingu je především nemožnost rozlišit právoplatný dotaz od útoku, což ale při rozumné spolehlivosti není ani prakticky možné. Příliš agresivní omezení by tak mohlo vést k přílišnému zahazování právoplatných dotazů, konzervativní zase k nižší účinnosti. BIND9 doporučuje agresivnější nastavení, Knot DNS je spolu s NSD spíše na konzervativní straně (RRL ve výchozím nastavení vypnuté, v dokumentaci 50 r/s).

Marek Vavruša

Autor:

Zanechte komentář