Brute-force elleni védekezés
Sziasztok!
Éppen egy login rendszert rakok össze, működik is szépen, viszont jó fejlesztőként gondolnom kell a kevésbé jóakaratú felhasználókra is, akik tesztelni fogják a rendszert, úgy hogy ráengednek pl. pár ezer request-et. Abban az esetben, ha jó felhasználónevet, de rossz jelszót ad meg a bejelentkezni kívánó user, a próbálkozást letárolom és 5 rossz próbálkozás után fél óráig nem engedem próbálkozni. Mit gondoltok, van-e hátulütője ennek a módszernek? Abban az esetben, ha viszont mindkét adat helytelen egy olyan megoldásra jutottam, hogy a válasz visszaadását késleltetem egy másodperccel (sleep-el). Ez azonban addig megoldás csak, amíg aszinkron lekéréseket csinál a user. Feltehetőleg azonban nem ez lesz a helyzet. Ekkor eszembe jutott, hogy egy IP-ről csak egy kérést engedélyezek egy időben, de ebben az esetben meg a proxy mögött levők szívják meg. Sajnos eddig jutottam! Volna-e valami ötletetek, amivel mindenki jól jár kivéve a támadókat?
■ Éppen egy login rendszert rakok össze, működik is szépen, viszont jó fejlesztőként gondolnom kell a kevésbé jóakaratú felhasználókra is, akik tesztelni fogják a rendszert, úgy hogy ráengednek pl. pár ezer request-et. Abban az esetben, ha jó felhasználónevet, de rossz jelszót ad meg a bejelentkezni kívánó user, a próbálkozást letárolom és 5 rossz próbálkozás után fél óráig nem engedem próbálkozni. Mit gondoltok, van-e hátulütője ennek a módszernek? Abban az esetben, ha viszont mindkét adat helytelen egy olyan megoldásra jutottam, hogy a válasz visszaadását késleltetem egy másodperccel (sleep-el). Ez azonban addig megoldás csak, amíg aszinkron lekéréseket csinál a user. Feltehetőleg azonban nem ez lesz a helyzet. Ekkor eszembe jutott, hogy egy IP-ről csak egy kérést engedélyezek egy időben, de ebben az esetben meg a proxy mögött levők szívják meg. Sajnos eddig jutottam! Volna-e valami ötletetek, amivel mindenki jól jár kivéve a támadókat?
Nagyon gyorsan felejtsd el a
Ha rossz jelszót ír be valaki, szerintem a legjobb megoldás vagy a bejelentkezés hosszabb időre történő tiltása emailes feloldás lehetőségével, vagy a fokozatosan egyre hosszabb időkre történő akadályozás, esetleg a kettő kombinálása. Pl.: 1-3 próbálkozás büntetés nélkül, utána hibánként 5-10-15 mp késleltetés, vagy fixen, vagy növekvő mértékben. Lehet tárolni a "támadó szándékú" fél IP-címét ehhez, és akkor nem kavar be a jogos felhasználó felé, meglehetősen impraktikussá téve a próbálkozásos törést.
Lehet trükközni mindenfélével, de arra kell figyelned, hogy ne tilts ki senki jogosult felhasználót véletlenül.
Könnyen kideríthető?
Azt nem írtad, hogy ha csak a
Szerintem célszerű külön felhasználónevet és display-nevet megadatni a júzerrel, és csak az utóbbit megjeleníteni. Mondjuk így is lesz, aki ugyan azt a nevet használja mindkét helyre, de az vessen magára. Ráadásul nem lesz egyértelmű, hogy ez-e a helyzet, vagy sem.
Mindenesetre annyi igaz, hogy ez a kisebbik része a védelemnek.
Egyébként ebben a cikkben van 1-2 tanulságos gondolat: http://blog.ircmaxell.com/2011/08/security-review-creating-secure-php.html Itt (is) szó van a bonyolultabb jelszó-hash generálásáról, ez egész konkrétan akkor hasznos, ha megszerezné valaki a felhasználói adatbázist.
Illetve a fenti hozzászólásom progresszív késleltetős megoldását is valahol olvastam, de arra nem emlékszem, hogy hol :/
Igaz
Igazad van, ez valóban kimaradt és elég láma lenne, ha ezt az esetet nem "védeném ki" :)
Köszi, érdekes cikknek tűnik, elolvasom mindenképp!
Nagyon gyorsan felejtsd el a
Ez a legértelmetlenebb security mítoszok egyike. Ha a felhasználó maga választhatja meg a usernevét, mint az összes létező webes alkalmazásban, akkor a regisztrációs oldalon jelezni kell neki, ha már létező usernevet választott, ami egy triviális eszközt ad a usernevek feltérképezésére, úgyhogy a világon semmi értelme szabotálni az oldal használhatóságát azzal, hogy eltitkoljuk előle, hogy a usernevét vagy a jelszavát rontotta el. (Okos weboldalak egyébként épp az ellenkezőjét csinálják: próbálnak minél több információt adni az elfelejtett login szívások elkerülésére.)
A késleltetés ettől függetlenül nem jó megoldás, mert DoS sebezhetőséget teremt.
Emailes feloldással könnyen végleg kizárhatod a felhasználót a saját fiókjából, ha elfelejti a jelszavát és az emailcímét is (esetleg az utóbbi már nem él). Az IP-alapú throttling jó dolog, de usernévhez kötve nem elég erős: simán lehet úgy is bruteforszolni, hogy választ a támadó találomra egy gyakori jelszót, és végigpróbálgatja az összes usernéven.
A cikk azért költői túlzásokkal él, DoS sebezhetőségnek állítja be azt, hogy két queryt használ a kód egy helyett, összemossa a collosion és a preimage támadást, és a key stretching is kicsit crypto nerd kategória: nagy webes szolgáltatásoknál illik ilyet csinálni, de egy átlagos weboldalnál az, hogy elviszik az adatbázist, és GPU-kból jelszótörő hálózatot építenek, nem egy valós fenyegetés.
Érdekes
1. Mindenképp érdemes valahogy a lehető legjobban titokban tartani a felhasználóinév adabázist (brute force szempontból). Például arra a problémára amit írsz (a regisztrációs oldalon jelezni kell neki, ha már létező usernevet választott) jó megoldásnak tűnik, ha a regisztráció egy erős chapta-val indul, és ha már létező usernevet választ a delikvens, akkor felkínálok neki egy párat ami még nincs, és ha sokat válogat, akkor új chapta-t is kérek.
2. A DOS támadásokat valahogy máshogy kéne kezelni (nem tudom hogy hogyan), ígyis-úgyis foglakozni kell vele, valahol egyébként is előfordulhat hogy lassabban válaszol a rendszered és akkor arra nyomulnak rá (egyébként meg ha mégsem, akkor max megtízszerezik a kérések számát és akkor már az egyébként gyors válaszaid is belassulnak).
A késleltetést nem feltétlenül úgy kell megoldani, hogy sleep-pel késleltetjük a http választ, hanem lehet úgy is, hogy gyorsan választ adunk, amiben nincsen semmi sem. Az egészet session szinten nyilvántartjuk, és megkérjük a klienst, hogy 5 másodperc múlva küldjön egy új kérést, amiben küldjük az igazi választ. (ha előbb jön a kérés, mint 5 mp, akkor megintcsak nem küldünk semmit) Mondhatnánk, hogy ezzel 1 kérés helyett 2 lesz, de a napi 1-2 bejelentkezés esetében ez nem számottevő pluszforgalom.
3. Lehet, hogy kényelmes dolog, ha a felhasználó számára nyilvánvalóvá tesszük, hogy a beírt felhasználónevet rontotta el, de ez is kompromisszum kérdése. Biztonsági szempontból szerintem nem olyan jó megoldás. Szerintem elvárható a felhasználóktól, hogy a ritkán előforduló "A felhasználói név vagy a jelszó hibás" üzenet esetén ne essen pánikba.
Nyilván nagyon szép és szuper újszerű, ha már a felhasználónév begépelésénél felkínálja a passzoló regisztráltakat, (kirakja az ikonodat már a jelszó beírása előtt is) és ez marketing szempontból előnyös (vagyis amíg kicsi a felhasználói közösséged ez az újszerű megoldás több felhasználót hozhat), de nem mindenfajta jellegű alkalmazásnál elfogadható, mivel teljesen nyílttá teszi a felhasználóinév (email cím??) adatbázist, és ezt még reklámozza is minden bejelentkezéskor. (Ez akár el is riaszthat felhasználókat)
3/1
Ami még tud működni, az a több lépcsős belépés (amihez több oldal letöltés kell), ezt ugyanis a netről letölthető brute force programok már nem szokták tudni.
Jobban belegondolva
Jobban belegondolva egyébként, ezt a brute-force elleni védekezést talán nem is php szintjén kellene lekezelni. Egy komolyabb támadás esetén még php-nak sem kell futni és megdögölhet a szerver vagy jöhet annyi request egyszerre a támadótól, hogy a tisztességes userekre nem jut idő...
nem kell
Szerintem nincs jó általános
Csak jó kompromisszum.
Vagy megvéded az oldalt, és használhatatlanná teszed, vagy használható, de kevésbé biztonságos.
Szóval ha megvagy vele, és tudod mire fog kelleni, akkor nem az a kérdés, hogy ez elég hatékony megoldás-e, hanem, hogy ez egy jó kompromisszum-e.
Ezt kell mérlegelni, és gondolom ez a login rendszer mondjuk nem egy banknak az oldala lesz.
Nem bank
Neeem, annyira azért nem nagyszabású oldal :) Csak fúrja az oldalam a kíváncsiság, hogy mit lehet kihozni maximálisan a szoftverből. Természetesen a usability a legfontosabb, a felhasználónak a lehető legkevesebb zavaró funkcionalitást szabad látnia. De azért a "hackereknek" sem akarom, hogy túl könnyű dolga legyen.
mindent késleltess
Ha csak a 3. (ugyanarra a felhasználónévre) történő próbálkozás után teszel be késleltetést, az csak azokkal a betörőkkel szemben nyújt védelmet, akik egy bizonyos felhasználó fiókját akarják feltörni. Ha "nagypályás" bruteforce-osok ellen akarsz korlátozást betenni, akkor minden bejelentkezési kérést késleltetni kell, még akkor is, ha jó a felhasználónév/jelszó páros. Nyugodtan lehet akár 5 másodpercet is késleltetni, ez simán elfogadható egy bejelentkezéshez (szerintem).
A böngészők eltárol(hat)ják a jelszót, ez amúgy sem biztonságos, ezért lehet furfangoskodni a bejelentkező űrlappal is. Az űrlap tartalmazzon sokkal több mezőt, mint ami szükséges, mondjuk százat (véletlenszerű nevekkel). Lehet akár százféle (kódgenerátorral gyártott vagy egyedileg elkészített) javascripted is, ami ezeket a mezőket pozícionálja és a feleslegeseket elrejti (csak a jókat jeleníti meg). Ezeket a JS kódokat akár többféle tömörítési/obfuszkáló eljárással mégtovább variálhatod.
A végén természetesen csak azokat az űrlapokat fogadod el, amikben csak a megfelelő két mező van kitöltve.
Mérlegelned kell a párhuzamos kéréseket is: valószínűleg egy IP címről egy időben amúgysem érkezik több bejelentkezési kérés (kicsi az esély, hogy 5 másodpercen belül akarnának ugyanabból az alhálózatból bejelentkezni -- ezt a te weboldalad és klienseid alapján felmérheted). Ha egy IP címről több kérés jön (mérlegelve a realitásokat) az ikszedik kérést már sokkal inkább késleltetheted, mondjuk azt is kiírhatod, hogy "egy kis türelmet kérek", és ezután jó sokat késleltethetsz ilyen esetben (ezt úgy kell beállítani, hogy normál esetben csak ritkán forduljon elő, de nyilvánvaló, hogy az egy IP-ről érkező bruteforce próbálgatásoknak gátat kell szabni)
Egy IP-ről érkező x időn belüli sokadik rossz próbálkozás után be lehet tenni chapta-t is.
Minél egyedibbre csinálod meg, annál macerásabb lesz kiismerni.
Valós felhasználóként
Ugyanígy nem tudom támogatni azt sem, hogy túlbonyolított űrlapok összeállítása miatt fusson plusz JavaScript a böngészőmben.
A 100 felesleges űrlap mező helyett legyen inkább egy.
Egy hidden mező, amibe az oldal összeállításakor bekerül egy generált, egyszer használatos kód/hash. A bejelentkezés elküldésekor ezt a hash-t lehet vizsgálni, ha nincs ott, nem megfelelő, vagy már fehasználták egyszer, akkor a kérést azonnal el lehet dobni.
A robotok többsége nem azt csinálja, hogy letölti a weboldalt, kitölti a mezőket, majd elküldi azt (tehát valós látogatást imitál), hanem direktben a feldolgozó URL-t hívogatja megfelelően felparaméterezve. Ezzel a megoldással viszont nem lesz meg az egyszer használatos hash, így nem lesz sikeres a hívás.
Persze ezen felül lehet még limitálni a max. lekérések számát adott IP-ről, adott idő alatt, stb.
Igazad van
A plusz javascript/html nem azért kell, mert a fejlesztő nem tud jobbat kitalálni (hiszen a legjobbat akarja) hanem azért, mert ez a legjobb, amit ki tud találni. ;-) (A cél érdekében, vagyis, hogy egy becsületes felhasználó fiókját ne lehessen brute force technikával feltörni) (egyébként ezeknek a javascripteknek a lefutása manapság már észrevehetetlenül gyors)
Nyilván a fapados brute force technikákat használók (akik nem igazán értenek hozzá, csak letöltenek egykét célszoftvert) nem kell túlbonyolítani a dolgot. Én olyan betörők visszafogására, kedvük szegésére gondoltam a 100 mezővel és 100 különböző feldolgozószkripttel, akik hajlandóak programozgatni, egyedileg alkalmazkodni az általad használt védelemhez. Az általad vázolt hashes módszer például könnyen kivédhető, ha ugyanúgy, mint a rendes felhasználó, a bejelentkezési link meghívása előtt lekérik a hasht is. (ahogy írod, valós látogatást imitálnak)
Viszont ha 100 mező van és 100 feldolgozó script, akkor legalább egy JS értelmezőt le kell hogy futtassanak, és ha nagyon variálod a megjelenítési trükköket (egymásra pakolás, túlpozícionálás, alfa vagy szín variálás, méretezés, stb), akkor még egy egy sor trükkre szüksége lesz ahhoz, hogy megállapítsa, hogy valójában hova, mely mezőkbe (vagy hogy úgy értelmezzük ahogy te mondod: milyen nevű get/post változókba) kell beleírni próbálkozásképp a felhasználónév/jelszó párost. (Meg lehet erősíteni ezt akár még egy flashes bejelentkező mezővel is, na akkor meg flash visszafejtés is kellene hozzá) (Ez egyfajta diszkrét chapta)
Nyilván túlzás amik az eszembe jutottak, ahogy előttem írták, kompromisszum az egész, de ahogy elgondolkodtam, eléggé meg lehet nehezíteni a bruteforce-ot ha akarjuk.
Ahol ilyen szintű védelemre
Szerintem.
Dehiszen
Védelem