ugrás a tartalomhoz

CSRF védekezés, jogok kiosztása, captcha használat

inf · 2010. Júl. 23. (P), 16.30

Sokat agyaltam azon, hogy milyen rendszerrel lehet megoldani a CSRF védekezést hatékonyan: most megszületett a megoldás.

Ami nyilvánvaló, hogy pusztán a HTTP referrer nem elég, mert nem támogatja az összes böngésző, emiatt ki kell küldeni egy olyan azonosítót, amit POST-ban visszaküld a felhasználó az űrlappal, és ezzel érvényesíti a kérését.

A gyakorlatban elég lenne pusztán annyi, hogy bejelentkezéskor az illető kap egy ilyen azonosítót (ezentúl: postId), és utána az összes űrlapjához ezt használja a hitelesítésre. Ez nagyon egyszerű és jól használható módszer.

Ha feltételezzük, hogy egy űrlapnak csak egy feldolgozója lehet (Ajax használatakor ez nem biztos), akkor viszont lehetséges az, hogy minden egyes űrlapot külön azonosítsunk. Ennek önmagában nem sok jelentősége van, viszont a későbbiekben kiderül, hogy össze lehet kapcsolni egy captchaval kapcsolatos probléma megoldásával és a jogok kezelésével.

A captchat szinte az összes helyen úgy használják, hogy egyszerre csak egy captcha van a sessionben, és az összes űrlapot azzal a captchaval lehet hitelesíteni. Ez azt eredményezi, hogyha egyszerre több captchas űrlap van megnyitva, akkor mindig a legutóbb megnyitott captchaját kell beírni bármelyikbe. Ez olyan alkalmazásoknál idegesítő lehet, ahol gyakran használnak captchat. Én konkrétan egy olyan oldalon futottam bele, ahonnan könyveket lehet letölteni a captcha beírása után. Először végignéztem a könyveket, hogy melyek azok, amik nekem kellenek, megnyitottam őket, megkaptam az űrlapjukat. Aztán amikor elkezdtem egymás után letölteni őket, akkor a letöltés előtt mindig frissítenem kellett az oldalt, hogy a megfelelő captcha képet lássam. Ez elég idegesítő volt.

A megoldás erre a problémára az lehet, hogyha a captcha képet és kódot hozzákötjük az aktuális űrlaphoz. Ehhez viszont tudni kell minden egyes űrlapot egyenként azonosítani.

A témához még hozzá tartozik a jogosultságok kezelése is. Én a jogok kezelését úgy oldottam meg, hogy az actionöket egyesével engedélyezem. Ez az én rendszeremben valahogy így megy:

$permissions=array(
	'Www' => array(
		'Articles' => array(
			'read' => true,
			'write' => true
		)
	)
);

Itt a www aldoménre az articles service (controller) read és write actionjei (metódus) engedélyezettek a felhasználó számára. Persze más rendszerek máshogy épülnek fel. A lényeg, hogyha bent van egy action a tömbben, akkor nálam joga van a felhasználónak használni azt; ha pedig nincs bent, akkor nincs joga hozzá.

Ha feltételezzük azt, hogy egy bizonyos űrlapot csak egy action dolgozhat fel (Ajax használatakor ez nem egyértelmű), akkor az egyes űrlapokat hozzá lehet kötni az őket feldolgozó actionhöz.

Az előzőekben az űrlap típusát az actionhöz kötöttük, az aktuális űrlapot a postId-hez, a captchat pedig az aktuális űrlaphoz. Ezekből a kapcsolatokból látszik, hogy egy rendszerbe össze lehet vonni ezeket az adatokat:

array(
	'action' => array(
		'postId' => 'captcha'
	)
)

Az összevont adatokat pedig be lehet illeszteni a jogosultság kezelő rendszerbe:

$permissions=array(
	'Www' => array(
		'Articles' => array(
			'read' => true,
			'write' => array(
				'1fd6b8ee5613' => '1745'
			),
			'edit' => array(
				'e7b2576243d2' => true,
				'629b9d7a624f' => true
			)
		)
	)
);

A fentiek alapján a felhasználónak joga van a cikkek olvasásához, írásához és szerkesztéséhez, és éppen egy cikket ír, amire a captcha kód 1745, két cikket pedig szerkeszt, a szerkesztés pedig nem kér captcha kódot.

A rendszert még nem teszteltem élesben, nem tudom, hogy mennyire terheli a rendszert a postId generálás, viszont ha túlságosan, akkor lehet kombinálni a két CSRF védelmi módszert: a belépéskor generálok egy hosszabb postId-t, az űrlapok azonosítására pedig csak azoknak a sorszámait használom.

 
1

Annyit hozzátennék, hogy a

inf · 2010. Júl. 23. (P), 20.32
Annyit hozzátennék, hogy a módszer nem tökéletes, mert nem lehet végtelen számú postId-t kiküldeni. Én elsősorban AJAX-os megoldásokkal foglalkozom mostanában, ott javascripttel vissza lehet jelezni bizonyos időközönként, hogy melyik postId van még használatban, illetve melyik nem. Továbbá meg lehet úgy is írni a rendszert, hogy egy bizonyos űrlaphoz (mondjuk login) csak egy postId-t küldjön akkor is, ha több ablakban van ugyanaz nyitva.
Szóval mint minden eszközt, ezt is csak ésszel lehet használni. Még épül a rendszer, amibe beteszem ennek a továbbfejlesztett változatát, csak azért tettem ki blogba, hátha lesznek építő jellegű hozzászólások.
2

Captcha olvasás

vami · 2010. Júl. 29. (Cs), 10.15
Ugyan nem kapcsolódik szorosan a témához de engem érdekelne hogyan lehet kivédeni, azt ha valaki géppel olvastatja be a captchat és próbálja kitölteni az űrlapot? Erre nincs valami megoldásod?
3

a gepi OCR meg nem elegge

Tyrael · 2010. Júl. 29. (Cs), 11.37
a gepi OCR meg nem elegge fejlett ahhoz, hogy az eros (ertsd tervezesi hibaval nem rendelkezo, kifejezetten OCR technikak ellen kifejlesztett) captcha-kat torje.

"kicsit" elavult, de kiindulasi pontnak jo:
http://caca.zoy.org/wiki/PWNtcha

Tyrael
4

Hát ez nem egyszerű kérdés,

inf · 2010. Júl. 29. (Cs), 22.01
Hát ez nem egyszerű kérdés, én egyelőre reCaptchan gondolkodom, mert ha egy digitalizálós cég nem tudta programmal kiolvastatni a szöveget, akkor más miért tudna jobb programot írni a témára? Még nem néztem meg, hogy ezzel a rendszerrel a reCaptcha mennyire összeegyeztethető.
Nem írtál konkrétumot, hogy milyen űrlapról van szó, úgy általánosságban pár dolgot tudsz szűrni, és meg tudod akadályozni, hogy valaki túl sűrűn küldjön űrlapot, de ezen kívül csak emberi beavatkozással tudod kitiltani a botot az oldalról, meg törölni az addigi tevékenységét.
Annyit tudsz tenni, ha ilyen történik, hogy keresel egy jobb captcha generálót, amit nem törnek fel.
5

Sokkal egyszerűbb eltárolni

tgr · 2010. Aug. 1. (V), 17.15
Sokkal egyszerűbb eltárolni egy fix értéket a sessionben, ahhoz hozzáfűzni a captcha megoldását, és az md5 hasht tenni az űrlapba mint POST paramétert. Űrlaponkénti session paraméterekre így semmi szükség.
6

Kifejtenéd? Nem teljesen

inf · 2010. Aug. 2. (H), 00.10
Kifejtenéd? Nem teljesen értem...
7

Egyirányú hashfüggvény + só,

tgr · 2010. Aug. 3. (K), 20.12
Egyirányú hashfüggvény + só, ugyanaz az elv, amivel a jelszavakat is védik.

Konfig fájlban:

global $secret_key = '043821e09f2811df981c0800200c9a66';
Belépéskor:

$_SESSION['csrf_token'] = uuid();
Űrlap generáláskor:

global $secret_key;
$token=md5($captcha_solution . $secret_key);
$form .= '<input type="hidden" name="captcha_token" value="'.$token.'"/>';
$form .= '<input type="hidden" name="csrf_token" value="'.$_SESSION['csrf_token'].'"/>';
Űrlap ellenőrzéskor:

global $secret_key;
if (md5($_POST['captcha'] . $secret_key) != $_POST['token']
    || $POST['csrf_token'] != $_SESSION['csrf_token']) {
  panic();
}
(A secret_key egyébként nem különösebben secret, akár lehet a CSRF tokent használni arra is.)
11

Ezzel mindössze annyi a gond,

inf · 2010. Aug. 3. (K), 21.42
Ezzel mindössze annyi a gond, hogy captcha kódot semmilyen formában nem szabad kitenni. Az md5 visszafejtése egy kattintás, anno amikor elindult a szivárványtáblázás, akkor volt még nem fizetősön olyan oldal, ahol sha1, md5, sha1(sha1), md5(md5) oda-vissza lehetett konvertálni tetszőleges 256 karakter hosszú stringekre. Ez sok éve volt....
Szóval sürgősen felejtsd el, hogy captcha ellenőrző kódot akár saltolva is kiteszel bárhova.

Mint írtam, ha nem akarsz minden egyes űrlapot azonosítani, csak crsf védelem kell, akkor elég annyi, hogy minden sessionhöz saját postId-t generáltatsz, és azt kéred vissza minden küldött űrlapnál.
13

Egy picikét el vagy tévedve a

tgr · 2010. Aug. 4. (Sze), 08.12
Egy picikét el vagy tévedve a számokkal. Egy md5 hash számítás kb. 400 órajel, ha csak kisbetűket és számokat veszünk, akkor 256 karakter 35^256 ~= 10^400 lehetőség. A manapság leggyorsabb szuperszámítógép a Jaguár petaflop körüli teljesítménnyel, ami kb. évi 10^20 md5 számítást tesz lehetővé. Az ismert univerzumban található atomok számát 10^80-ra becsülik, ha mindegyikre ráültetnél egy szuperszámítógépet, még mindig 10^100 évre lenne szükséged, márpedig ha hihetünk a fizikusoknak, az atomok mintegy 10^40 éven belül megszűnnek létezni.

A példában szereplő 32 karakteres kulcs már bőven túl van a mai számítógépek képességein, arról nem beszélve, hogy a szivárványtábla nagy méreteknél már a véges tárhely miatt nem túl gyors, márpedig a captchatörés tipikusan olyan támadásokhoz kell, ahol a sebesség nagyon számít. (Viszonyításképpen, az Ophcrack egy 8 gigás rainbow táblával tud max 14 karakteres jelszavakat törni, és egy törés percekig tart, ami nagyon jó, ha egy szerverre való betöréshez kell, de ha spammeléshez, akkor már nem annyira.) De ha nagyon paranoid vagy, nyugodtan használhatsz UUID helyett egy ezer karakteres random sztringet.
15

Hmm, lehet, hogy el vagyok

inf · 2010. Aug. 4. (Sze), 13.24
Hmm, lehet, hogy el vagyok tévedve a számokkal. Talán kicsit túlzóak az emlékeim, nem emlékszem teljesen tisztán, csak arra, hogy kipróbáltam egy oldalon ilyen táblát, amikor még ingyenes volt, és az már sok éve volt. Meg arra is, hogy kivettem valahonnan egy random szövegrészt, lekódoltam, beraktam a táblába, és visszaalakította, és az a szövegrész nem 14 karakter volt... (Nem számoltam utána, hogy ez lehetséges e, lehet, hogy dinamikusan bővülő volt az ottani tábla, és azt tárolta le, amit már a felhasználók beírtak neki, mert az oldallal csináltam a lekódolást is.)

Egyébként ez egy elv, hogy nem teszem ki visszafejthető formában a captcha kódot, amit kérek. Feleslegesen nem nyitok új támadási pontot. Bőven elég az, hogy a captchat is beolvastathatják, ha rossz a kódja.
17

Hosszú szövegeket md5-ből

tgr · 2010. Aug. 4. (Sze), 21.41
Hosszú szövegeket md5-ből visszaállítani még akkor sem lehetne, ha lenne egy végtelenül gyors számítógéped: az md5 egy 128 bites kulcsot generál, ha a bemenet információtartalma ennél nagyobb volt, akkor a művelet nem egyértelmű. Kisbetűket és számokat (36 féle karakter) feltételezve 128 bit kb. 25 karakternyi információ, a 26 karakteres sztringek között már 36 lesz egy-egy adott md5 kulcshoz, a 27 karakteresek között 36*36 stb.

A captchának éppenséggel az a lényege, hogy visszafejthető :) de ettől eltekintve, egy sózott md5-ben semmi visszafejthető nincsen. Ez egy standard biztonságtechnikai módszer, ezt használják jelszavak védelmére, hasonló konstrukció van a HTTPS protokollban, ha szerinted ez támadási pont, akkor valószínűleg nem érted, hogyan működik. Ha valaki rájönne, hogyan törhető az md5 (ami elméletileg persze lehetséges), aligha az lenne az első dolga, hogy szaladjon feltörni a te captchádat.
18

Az viszont csúnya hiba a

tgr · 2010. Aug. 4. (Sze), 21.59
Az viszont csúnya hiba a példámban, hogy ugyanazt a megoldás-hash párt akárhányszor be lehet küldeni. Le lehetne tárolni a sessionben egy tömbben az "elhasznált" kulcsokat, de azzal meg nincs sokkal előbbre az ember, mintha űrlapongenerálásonként egyedi kulcsokat használna...
19

Az elhasznált kulcsok törlése

inf · 2010. Aug. 5. (Cs), 06.40
Az elhasznált kulcsok törlése nem annyira rossz elgondolás, viszont azzal is para van, mert ha többször szerepel ugyanaz a kulcs, akkor a második előfordulásnál már nem engedélyezi a rendszer.
Szóval ez sem jött be. Ha meg egy kulcsot többször engedélyezel, akkor meg megint az van, mint írtad, hogy végtelenszer beküldhetik ugyanazt.

Annyit lehet csinálni a te módszereddel, hogy generálsz a captcha mellé még egy véletlen string-et, amit visszakérsz az űrlappal. Így meg lehet annyira növelni a variációk számát, hogy szinte nulla legyen az ismétlődés esélye. Aztán így már lehet érvényteleníteni az elhasznált kódokat.

Végülis lehetséges megoldás, de ugyanúgy véletlen azonosító kell minden captchas űrlaphoz, mint annál, amit én írtam. (Én inkább maradok a saját megoldásomnál :-P)
14

Egyébként ha valaki nagyon

tgr · 2010. Aug. 4. (Sze), 08.20
Egyébként ha valaki nagyon fel akar törni egy captchát (és sima karakterfelismeréssel nem tudja - márpedig a gyakorlatban használt captchák 99%-át fel lehet), az kiteszi egy pornószájtra, vagy fizet ezer captchánként egy fillért egy indiai vállalkozónak. Ezek ellen nem nagyon lehet mit csinálni.
16

Csak vigyázz, hogy ne ess te

inf · 2010. Aug. 4. (Sze), 13.26
Csak vigyázz, hogy ne ess te is abba a hibába, mint én, hogy csak így dobálózol a számokkal forrás nélkül... :-)
8

Egyirányú hashfüggvény + só,

tgr · 2010. Aug. 3. (K), 20.12
Egyirányú hashfüggvény + só, ugyanaz az elv, amivel a jelszavakat is védik.

Konfig fájlban:

global $secret_key = '043821e09f2811df981c0800200c9a66';
Belépéskor:

$_SESSION['csrf_token'] = uuid();
Űrlap generáláskor:

global $secret_key;
$token=md5($captcha_solution . $secret_key);
$form .= '<input type="hidden" name="captcha_token" value="'.$token.'"/>';
$form .= '<input type="hidden" name="csrf_token" value="'.$_SESSION['csrf_token'].'"/>';
Űrlap ellenőrzéskor:

global $secret_key;
if (md5($_POST['captcha'] . $secret_key) != $_POST['token']
    || $POST['csrf_token'] != $_SESSION['csrf_token']) {
  panic();
}
(A secret_key egyébként nem különösebben secret, akár lehet a CSRF tokent használni arra is.)
9

Az egyedi postId másfelől

tgr · 2010. Aug. 3. (K), 20.16
Az egyedi postId másfelől kiválóan használható a mentés gombra való duplakattintás ennél valamivel elegánsabb kezelésére ;-)
10

Na tessék

Joó Ádám · 2010. Aug. 3. (K), 21.34
Most már nem törölhetem ki a duplát…
12

Ilyen az élet :-)

inf · 2010. Aug. 3. (K), 21.43
Ilyen az élet :-)