
Podjetje Variti razvija zaščito pred boti in DDoS napadi ter izvaja stresne in obremenitvene teste. Na konferenci HighLoad++ 2018 smo govorili o tem, kako zaščititi vire pred različnimi vrstami napadov. Na kratko: izolirajte dele sistema, uporabljajte oblačne storitve in CDN ter redno posodabljajte. Vendar brez specializiranih podjetij za zaščito se vseeno ne boste mogli zaščititi 🙂
Pred branjem besedila se lahko seznanite s kratkimi tezami .
Če ne marate branja ali preprosto želite gledati video, je posnetek našega predavanja spodaj v skrivenem delu.
Posnetek predavanja

Mnoge družbe že znajo izvajati obremenitvene teste, vendar ne vse izvajajo stresne teste. Nekateri naši naročniki menijo, da je njihova spletna stran neprobojena, ker imajo visokointenzivni sistem, ki dobro ščiti pred napadi. Mi pa dokazujemo, da to ni čisto res.
Seveda pred izvedbo testov pridobimo dovoljenje naročnika z podpisom in žigom, in z našo pomočjo DDoS napadov na nikogar ni mogoče izvesti. Testiranje poteka v času, ki ga izbere naročnik, ko je obremenitev njegovega vira minimalna in težave z dostopom ne vplivajo na stranke. Poleg tega, ker se lahko med testiranjem vedno zgodi kaj nepričakovanega, imamo stalni stik z naročnikom. To nam omogoča, da ne le poročamo o doseženih rezultatih, ampak tudi spreminjamo nekatere stvari med testiranjem. Ob zaključku testiranja vedno pripravimo poročilo, v katerem navajamo odkrite pomanjkljivosti in dajemo priporočila za odpravo šibkih mest spletne strani.
Kako delamo
Pri izvajanju testiranja emuliramo botnet. Ker delamo s strankami, ki niso v naših omrežjih, da test ne bi končal takoj v prvi minuti zaradi delovanja omejitev ali zaščite, nalagamo obremenitev ne iz enega IP, temveč iz svoje podmrežne skupine. Poleg tega imamo za ustvarjanje bistvene obremenitve svoj dovolj zmogljiv testni strežnik.
Postulati
Veliko — ne pomeni dobro
Čim manjim opterećenjem možemo doći do kvara resursa, to je bolje. Ako uspemo da napravimo situaciju da sajt prestane da funkcioniše samo od jednog zahteva u sekundi, ili čak od jednog zahteva u minutu, to bi bilo odlično. Zato što po zakonu ružnoće, korisnici ili zlonamernici slučajno padnu baš na ovu ranjivost.
Delimični kvar je bolji od potpunog
Uvek savetujemo da sistemi budu heterogeni. I treba ih deliti upravo na fizičkom nivou, a ne samo kontejnerizacijom. U slučaju fizičkog razdvajanja, čak i ako nešto na sajtu zakaže, postoji velika verovatnoća da neće doći do potpunog prestanka rada, a korisnicima će biti omogućen pristup barem delu funkcionalnosti.
Ispravna arhitektura je osnova otpornosti
Otpornost resursa i njegova sposobnost da izdrži napade i opterećenja treba da se ugrade u fazi projektovanja, zapravo u fazi crtanja prvih blok dijagrama u svinčniku. Jer ako se unesu fatalne greške, moguće ih je ispraviti kasnije, ali veoma je teško.
Dobar treba da bude ne samo kod, već i konfiguracija
Mnogi misle da dobra razvojna ekipa garantuje otpornost servisa. Dobra razvojna ekipa je zaista potrebna, ali takođe je potrebna i dobra eksploatacija, dobar DevOps. To znači da su potrebni stručnjaci koji će pravilno konfigurirati Linux i mrežu, pravilno napisati konfiguracije u nginx, postaviti limite i ostalo. U suprotnom, resurs će dobro raditi samo u testu, a u produkciji će s vremenom doći do kvara.
Razlike između opterećenja i stres testiranja
Opterećenje testiranje omogućava da otkrijemo granice funkcionisanja sistema. Stres testiranje je usmereno na pronalaženje slabih tačaka sistema i koristi se da se taj sistem pokvari i vidi kako će se ponašati u procesu kvara određenih delova. Pri tom tip opterećenja obično ostaje nepoznat klijentu do početka stres testiranja.
Odlike L7 napada
Vrste opterećenja obično delimo na opterećenja na L7 i L3&4 nivou. L7 je opterećenje na nivou aplikacije, najčešće se pod tim podrazumeva samo HTTP, dok mi podrazumevamo bilo koje opterećenje na nivou TCP protokola.
L7 напadi imajo določene značilnosti. Prvič, prihajajo neposredno v aplikacijo, kar pomeni, da jih je z omrežnimi sredstvi težko odpraviti. Takšni napadi uporabljajo logiko in zaradi tega zelo učinkovito in z malo prometa porabljajo CPU, pomnilnik, disk, bazo podatkov in druge vire.
HTTP Flood
Pri katerem koli napadu je lažje ustvariti obremenitev kot jo obdelovati, in to velja tudi za L7. Napadni promet ni vedno enostavno razlikovati od legitimnega, najpogosteje je to mogoče narediti po pogostosti, vendar če je vse dobro načrtovano, je nemogoče razumeti iz logov, kje je napad in kje so legitimni zahtevki.
Kot prvi primer si poglejmo napad HTTP Flood. Iz grafikona je razvidno, da so taki napadi običajno zelo močni; v spodnjem primeru je vrhunec števila zahtevkov presegel 600.000 na minuto.

HTTP Flood je najlažji način za ustvarjanje obremenitve. Običajno se za to vzame nek instrument za obremenitveno testiranje, na primer ApacheBench, in se zastavi zahteva in cilj. Pri takšnem preprostem pristopu je velika verjetnost, da naletimo na predpomnjenje strežnika, vendar ga je enostavno obiti. Na primer, tako da dodamo naključne vrstice v zahtevo, kar prisili strežnik, da vedno vrne svežo stran.
Prav tako ne smemo pozabiti na user-agent pri ustvarjanju obremenitve. Mnogi user-agenti priljubljenih orodij za testiranje se filtrirajo s strani sistemskih administratorjev, in v tem primeru lahko obremenitev preprosto ne doseže backend-a. Rezultat se lahko znatno izboljša, če v zahtevo vključimo bolj ali manj veljaven naslov iz brskalnika.
Kljub preprostosti napada HTTP Flood ima tudi svoje pomanjkljivosti. Prvič, za ustvarjanje obremenitve so potrebne velike zmogljivosti. Drugič, taki napadi se zelo enostavno odkrijejo, zlasti če prihajajo iz enega naslova. Rezultat je, da se zahtevki takoj začnejo filtrirati bodisi s strani sistemskih administratorjev bodisi celo na ravni ponudnika.
Kaj iskati
Da bi zmanjšali število zahtevkov na sekundo, ne da bi pri tem izgubili učinkovitost, je potrebno nekaj domišljije in raziskovanja spletne strani. Obremenitev lahko povzroči ne samo povezava ali strežnik, ampak tudi posamezni deli aplikacije, kot so baze podatkov ali datotečni sistemi. Pravno je dobro raziskati mesta na spletni strani, ki izvajajo velike izračune: kalkulatorji, strani za izbiro produktov in podobno. Končno se pogosto zgodi, da obstaja nek php skript, ki generira stran iz več sto tisoč vrstic. Tak skript prav tako znatno obremeni strežnik in lahko postane tarča napada.
Kje iskati
Ko skeniramo vir pred testiranjem, najprej pogledamo seveda na samo spletno stran. Iščemo različna polja za vnos, težke datoteke — na splošno vse, kar lahko povzroči težave viru in upočasni njegovo delovanje. Tukaj pomagajo enostavna orodja za razvijalce v Google Chrome in Firefoxu, ki prikazujejo čas odziva strani.
Prav tako skeniramo poddomene. Na primer, obstaja nek spletni prodajalec, abc.com, in ima poddomeno admin.abc.com. Verjetno gre za admin panel z prijavo, vendar če vanj spuščamo obremenitev, lahko povzroči težave za glavni vir.
Spletna stran ima lahko poddomeno api.abc.com. Verjetno gre za vir za mobilne aplikacije. Aplikacijo je mogoče najti v App Store ali Google Play, namestiti posebno dostopno točko, dekonstruirati API in registrirati testne račune. Problem je v tem, da mnogi ljudje pogosto mislijo, da je vse, kar je zaščiteno z avtentikacijo, neobranljivo za napade na zavrnitev storitve. Domnevno je avtentikacija najboljša CAPTCHA, vendar to ni res. Ustvarjanje 10-20 testnih računov je enostavno, in ko jih enkrat ustvarimo, pridobimo dostop do kompleksne in ne zaščitene funkcionalnosti.
Seveda gledamo zgodovino, robots.txt in WebArchive, ViewDNS in iščemo stare verzije vira. Včasih se zgodi, da so razvijalci izdali, recimo, mail2.yandex.net, medtem ko je stara različica, mail.yandex.net, ostala. Ta mail.yandex.net ne preneha s podporo, na njega se ne namenjajo razvojni viri, vendar še naprej porablja podatkovno bazo. Tako je mogoče z uporabo stare različice učinkovito izkoristiti vire backend-a in vsega, kar stoji za oblikovanjem. Seveda se to ne zgodi vedno, vendar se s tem kljub temu soočamo kar pogosto.
Seveda, analiziramo vse parametre poizvedbe, strukturo piškotkov. Lahko na primer vpišemo vrednost v JSON polje znotraj piškotka, ustvarimo veliko hierarhijo in prisilimo vir, da deluje nerazumno dolgo.
Obremenitev pri iskanju
Prvo, kar pride na misel pri preučevanju spletnega mesta, je obremenitev baze podatkov, saj skoraj vsak ima iskalnik, in skoraj vsi so, na žalost, slabo zaščiteni. Razvijalci iz neznanega razloga ne posvečajo dovolj pozornosti iskanju. Vendar je tukaj ena priporočilo — ne smete opravljati enotnih poizvedb, saj se lahko srečate z okrepljenjem, kot pri HTTP floodu.
Prav tako naključno poizvedovanje v bazo podatkov ni vedno učinkovito. Bolje je ustvariti seznam ključnih besed, ki se nanašajo na iskanje. Če se vrnemo k primeru spletne trgovine: recimo, da spletna stran prodaja avtomobilske pnevmatike in omogoča vnos premera pnevmatik, tip avtomobila in druge parametre. Kombinacije relevantnih besed bodo povzročile, da bo baza podatkov delovala v mnogo bolj zapletenih pogojih.
Poleg tega je smiselno uporabiti paginacijo: iskanju je veliko težje vrniti predzadnjo stran rezultatov kot prvo. To pomeni, da lahko s paginacijo nekoliko popestrite obremenitev.
V spodnjem primeru prikazujemo obremenitev pri iskanju. Vidimo, da je že od prve sekunde testa z desetimi poizvedbami na sekundo spletna stran padla in ni odgovarjala.

Kaj pa, če iskanja ni?
Če iskanja ni, to ne pomeni, da spletna stran ne vsebuje drugih ranljivih vnosnih polj. Takšno polje je lahko avtentikacija. Zdaj razvijalci raje uporabljajo zapletene hashe, da zaščitijo bazo prijav pred napadi z mavričnimi tabelami. To je dobro, vendar takšni hashi porabijo velike CPU vire. Velik pretok lažnih avtentikacij privede do odpovedi procesorja, in posledično spletna stran preneha delovati.
Prisotnost različnih obrazcev na spletnem mestu za komentarje in povratne informacije je priložnost, da tja pošljemo zelo velike besedila ali preprosto ustvarimo množičen spamming. Včasih spletna mesta sprejemajo tudi vgrajene datoteke, vključno s formatom gzip. V takem primeru vzamemo datoteko velikosti 1TB, jo z gzip-om stisnemo na nekaj bajtov ali kilobajtov in jo pošljemo na spletno stran. Nato se razpakira in rezultat je zelo zanimiv.
Rest API
Želeli bi posvetiti malo pozornosti trenutno popularnim uslugama poput Rest API. Zaštititi Rest API mnogo je teže nego običnu web stranicu. Čak i banalne metode zaštite od pokušaja pogađanja lozinki i druge nelegitimne aktivnosti ne rade za Rest API.
Rest API se vrlo lako može slomiti, jer se direktno obraća bazi podataka. Posljedice prekida rada takve usluge mogu značajno utjecati na poslovanje. Naime, Rest API obično povezuje ne samo glavnu web stranicu, već i mobilnu aplikaciju, kao i neke unutarnje poslovne resurse. Ako sve to prestane s radom, učinak je mnogo jači nego u slučaju kvara jednostavne web stranice.
Opterećenje pri radu s teškim sadržajem
Ako nam predlažu testirati neku običnu jednostranu aplikaciju, odredišnu web stranicu, poslovnu vizitku, koje nemaju složenu funkcionalnost, tražimo teški sadržaj. Na primjer, velike slike koje server šalje, binarne datoteke, pdf dokumentaciju — pokušavamo sve to preuzeti. Ovi testovi dobro opterećuju datotečni sustav i zagušuju kanale, stoga su učinkoviti. To jest, čak i ako ne srušite server preuzimanjem velike datoteke pri malim brzinama, samo ćete zagušiti kanal ciljanog servera, a tada će doći do nepristupačnosti usluge.
Na primjeru takvog testa vidi se da je pri brzini od 30 RPS stranica prestala odgovarati ili je davala 500 greške servera.

Ne smijemo zaboraviti ni na postavke servera. Često se može vidjeti da je osoba kupila virtualnu mašinu, postavila Apache, konfigurirala sve prema zadanoj postavci, postavila php aplikaciju, i ispod možemo vidjeti rezultat.

Tu je opterećenje išlo u korijen i iznosilo svega 10 RPS. Čekali smo 5 minuta i server je pao. Do kraja, istina, nije poznato zašto je pao, ali postoji pretpostavka da je jednostavno 'pojeo' previše memorije i zato je prestao odgovarati.
Wave based
V zadnjih dveh letih so postali precej priljubljeni valovni napadi. To je povezano s tem, da številne organizacije kupujejo različne naprave za zaščito pred DDoS-om, ki za začetek filtriranja napada zahtevajo določeno časovno obdobje zbiranja statistike. To pomeni, da v prvih 30-40 sekundah napada ne filtrirajo, ker zbirajo podatke in se učijo. Zato je v teh 30-40 sekundah mogoče na spletno mesto poslati toliko prošenj, da je vir dolgo nedostopen, dokler se ne razbremeni vseh pozivov.
V primeru napada spodaj je bil interval 10 minut, po katerem je prišla nova, spremenjena serija napada.

To pomeni, da je zaščita opravila usposabljanje in začela filtrirati, toda prišla je nova, povsem drugačna serija napada, in zaščita je spet začela učenje. Dejansko filtracija preneha delovati, zaščita postane neučinkovita in spletna stran postane nedostopna.
Za valovne napade so značilni zelo visoki vrhovi, lahko dosežejo sto tisoč ali milijon zahtevkov na sekundo v primeru L7. Če govorimo o L3 in L4, lahko tam govorimo o stotinah gigabitov prometa ali, ustrezno, stotinah mpps, če štejemo v paketih.
Težava takšnih napadov je v sinhronizaciji. Napadi prihajajo iz botnetov in za ustvarjanje zelo velikega enkratnega vrha je potrebna visoka stopnja sinhronizacije. Ta koordinacija ne uspe vedno: včasih nastane nekakšen parabolni vrh, ki izgleda precej obžalovanja vredno.
Ne živi le s HTTP-jem
Poleg HTTP na ravni L7 radi izkoriščamo tudi druge protokole. Običajno ima navadna spletna stran, še posebej pri običajnem gostovanju, izpostavljene poštne protokole in MySQL. Poštni protokoli so manj dovzetni za obremenitve kot podatkovne baze, vendar jih je mogoče obremeniti dovolj učinkovito in na izhodu dobiti preobremenjen CPU na strežniku.
Uspešno smo uporabili ranljivost SSH iz leta 2016. Sedaj je ta ranljivost pri večini popravljena, vendar to ne pomeni, da v SSH ne moremo obremeniti. Lahko. Preprosto ustvarimo ogromno obremenitev avtentifikacij, SSH skoraj povsem porabi CPU na strežniku in potem spletna stran pade že pri eni do dveh prošenj na sekundo. Ustrezno teh ena-dve prošenj po dnevnikih ni mogoče razlikovati od legitimne obremenitve.
Ohranjajo se tudi številne povezave, ki jih odpiramo na strežnikih. Pred časom je s tem grešil Apache, sedaj pa to pogosto počne tudi Nginx, saj je pogosto nastavljen na privzeto. Število povezav, ki jih lahko Nginx drži odprte, je omejeno, zato odpiramo to število povezav in nove povezave Nginx ne sprejema, kar pomeni, da spletna stran ne deluje.
Naš testni klaster ima dovolj CPU, da napade SSL handshake. Na splošno, kot kaže praksa, tudi botneti to občasno radi počnejo. Po eni strani je jasno, da brez SSL ni mogoče, saj gre za uvrstitev v Google, rangiranje in varnost. Po drugi strani pa ima SSL, žal, težave s CPU.
L3&4
Ko govorimo o napadu na ravneh L3&4, praviloma govorimo o napadu na ravni kanala. Takšna obremenitev je skoraj vedno prepoznavna od legitimne, razen če gre za napad SYN-flood. Problem SYN-flood napadov za zaščitna sredstva je velik obseg. Največja vrednost L3&4 je bila 1,5-2 Tbit/s. Tak promet je zelo težko obdelati tudi velikim podjetjem, vključno z Oracle in Google.
SYN in SYN-ACK so paketi, ki se uporabljajo pri vzpostavljanju povezave. Zato je SYN-flood težko razlikovati od legitimne obremenitve: ni jasno, ali gre za SYN, ki pride za vzpostavitev povezave, ali del poplave.
UDP-flood
Običajno nimajo napadalci takih zmogljivosti, kot jih imamo mi, zato se za organizacijo napadov lahko uporabi amplifikacija. To pomeni, da napadalec skenira internet in najde bodisi ranljive bodisi nepravilno nastavljene strežnike, ki, na primer, kot odgovor na en SYN-paket, odgovorijo s tremi SYN-ACK. S ponarejanjem izvorne naslova s tistega ciljanega strežnika lahko z enim paketom povečamo moč, recimo, trikrat, in preusmerimo promet na žrtev.

Problem amplifikacij je v njihovi težki odkritosti. Med zadnjimi primeri lahko omenimo odmeven primer z ranljivim memcached. Poleg tega je danes na voljo veliko naprav IoT, IP-kamer, ki so tudi večinoma nastavljene na privzeto, in nepravilno, zato napadalci to pogosto izkoriščajo za napade.

Zapleten SYN-flood
SYN-flood je verjetno najzanimivejša vrsta napadov z vidika razvijalca. Težava je v tem, da sistemski skrbniki pogosto uporabljajo blokado po IP-ju kot zaščito. Pri tem pa zaradi blokade po IP-ju trpijo ne le skrbniki, ki delujejo po skriptih, temveč tudi nekateri sistemi zaščite, ki se kupijo za velike denarce.
Takšna metoda se lahko konča katastropalno, saj če napadalci ponaredijo IP-naslove, bo podjetje blokiralo lastno podsistem. Ko požarni zid blokira lastni grozd, bodo zunanje interakcije propadle in vir bo prenehal delovati.
Poleg tega ni težko doseči blokade lastne mreže. Če ima stranka v pisarni Wi-Fi omrežje ali če se delovanje virov meri z različnimi monitorji, vzamemo IP naslov tega monitorja ali pisarniškega Wi-Fi odjemalca in ga uporabimo kot vir. Tako je vir na videz dostopen, vendar so ciljni IP naslovi blokirani. Tako se lahko blokira Wi-Fi omrežje konferencije HighLoad, kjer se predstavlja nov izdelek podjetja, kar povzroči določene poslovne in gospodarske stroške.
Med testiranjem ne moremo uporabljati amplifikacije preko memcached z nekaterimi zunanjimi viri, ker imamo dogovore o usmerjanju prometa le v dovoljene IP naslove. Zato uporabljamo amplifikacijo preko SYN in SYN-ACK, pri čemer na enega poslano SYN sistem odgovori z dvema ali tremi SYN-ACK, učinek napada pa se poveča dvakrat ali trikrat.
Orodja
Eden od glavnih orodij, ki jih uporabljamo za obremenitev na ravni L7, je Yandex-tank. Konkretno se kot puška uporablja fantom, poleg tega pa imamo več skriptov za generiranje nabojev in za analizo rezultatov.
Za analizo omrežnega prometa uporabljamo Tcpdump, za analizo strežnika pa Nmap. Za ustvarjanje obremenitve na ravni L3&4 uporabljamo OpenSSL in malo lastne magije s knjižnico DPDK. DPDK je knjižnica podjetja Intel, ki omogoča delo z omrežnim vmesnikom brez Linuxovega sklada, kar povečuje učinkovitost. Seveda DPDK ne uporabljamo le na ravni L3&4, temveč tudi na ravni L7, saj omogoča ustvarjanje zelo visokega prometa, do več milijonov zahtevkov na sekundo z ene naprave.
Prav tako uporabljamo določene generatore prometa in posebna orodja, ki jih pišemo za specifične teste. Če se spomnimo ranljivosti pod SSH, jo z zgoraj navedenim naborom ni mogoče izkoristiti. Če napadamo poštni protokol, uporabimo poštne pripomočke ali preprosto napišemo skripte zanje.
Zaključki
Kot zaključek bi rad rekel:
- Poleg klasičnega obremenitvenega testiranja je nujno potrebno izvajati tudi stresno testiranje. Imamo pravi primer, ko je podizvajalec partnerja izvedel le obremenitveno testiranje. To je pokazalo, da vir prenese običajno obremenitev. A potem se je pojavila nenavadna obremenitev, obiskovalci spletne strani so vir začeli uporabljati nekoliko drugače - in podizvajalec se je na izhodu sesedel. Tako je vredno iskati ranljivosti, tudi če ste že zaščiteni pred DDoS napadi.
- Potrebno je izolirati posamezne dele sistema od drugih. Če imate iskanje, ga je treba prenesti na ločene naprave, torej ne samo na docker. Ker če iskanje ali avtentikacija odpove, vsaj nekaj še vedno deluje. V primeru spletne trgovine bodo uporabniki še vedno lahko našli izdelke po katalogu, prešli iz agregatorja, kupovali, če so že avtentikovani, ali se avtentikovali prek OAuth2.
- Ne smete zanemariti vseh mogočih oblačnih storitev.
- Uporabite CDN ne le za optimizacijo omrežnih zamud, ampak tudi kot sredstvo zaščite pred napadi na izčrpavanje pasovne širine in preprosto flood v statiko.
- Potrebno je uporabljati specializirane zaščitne storitve. Pred napadi L3&4 na ravni kanala se sami ne morete zaščititi, ker verjetno preprosto nimate dovolj pasovne širine. Pred napadi L7 se tudi verjetno ne boste mogli obraniti, ker so lahko zelo veliki. Poleg tega je iskanje manjših napadov še vedno prerarogativa specializiranih storitev in posebnih algoritmov.
- Redno se posodabljajte. To se nanaša ne le na jedro, ampak tudi na SSH daemon, še posebej, če so odprti navzven. Na splošno je treba posodabljati vse, ker težko sami spremljate določene ranljivosti.
Izvor: habr.com
