Ochrana před cross-site request forgery

Co to je CSRF

Cross-site request forgery je velmi nebezpečná technika, kdy útočník na své stránce nebo stránce trpící XSS (lze tam zveřejnit škodlivý kód) zveřejní kód, který u napadeného (který si poškozenou stránku zobrazí) vyvolá požadavek do nějaké webové aplikace, ve které je napadený příhlášen (GMail, e-Banking, administrace blogu). Tento požadavek provede nějakou nechtěnou akci - změní heslo, smaže obsah atd.

Obrana

Spolehlivou metodou, jak CSRF zabránit, je přidat do všech citlivých formulářů a odkazů na akce (např. smaž uživatele) další dvě položky:

  • náhodný klíč (např. číslo)
  • hash klíče a nějakého tajného obsahu (např. hash hesla)

Tedy něco takového:

$key = rand(0, 100);
$hash = md5($user->password . $key);
echo '<input type="hidden" name="key" value="'.$key.'" />';
echo '<input type="hidden" name="hash" value="'.$hash.'" />';

Po odeslání formuláře pak zkontrolujeme získané údaje:

$hash = md5($user->password . $_POST['key']);
if ($hash !== $_POST['hash'])
    throw new Exception('Cross site request forgery attact from IP: ' . $_SERVER['REMOTE_ADDR'], 401);

evaluation

Komentáre

[1] Lukyer
2008-12-25 10:02:32

Jen bych dodal, ze nekdy je treba takto osefovat i GET pozadavky, ktere muzou byt taktez nebezpecne. Ja osobne generuju pri kazdem nacteni stranky nahodny retezec zakodovany v md5 do $_SESSION['csrf'] a pak jej u kazdeho formulare vypisuju a po pouziti opet zmenim ... tim se vylouci moznost napriklad dvojiteho pridani prispevku refreshem, nebo znovunactenim opery (ktera automaticky reloadne posledni panely)

Na tento komentár odpovedal [2] Dundee
Na tento komentár odpovedal [4] Pavel Šindelka
[2] Dundee
2008-12-25 10:09:35

#1 Lukyer: GET požadavky = odkazy na akce (viz článek)

Tvé řešení se mi líbí, je ještě elegantnější.

[3] Lukyer
2008-12-25 10:31:05

Omlouvam se, nevsiml jsem si. Rozhodne ale nepouzivat jako csrf nejaky znamy udaj, jako napriklad session id. Da se na mnoho mistech zjistit a pak je jakakoliv ochrana csrf v haji ... Je az neuveritelne kolik webu, i opensource projektu tuto naprosto zasadni bezpecnostni chybu ignoruji, hlavne v pripade administraci ruznych webu :-/ Kolikrat neni problem si v eshopu timto objednat cokoliv na svou adresu ale na cizi ucet, kdy v pripade automatickeho prevodu z karty je problem ... Tezko potom vymahat to, ze si to uzivatel neobjednal sam. A nejhorsi ze je s tim sam uzivatel nemuze nic delat...

2008-12-25 11:55:41

#1 Lukyer: Nedělá to problémy při práci ve více oknech s téže aplikací najednou?

[5] Lukyer
2008-12-25 12:08:25

Osobně pracuji jen ve více panelech téže aplikace, ale mám napsanou správu sessions tak, že to problém nedělá. Problém by dělalo kdyby uživatel udělal nejaký "mezní krok" mezi požadavky, což se stát imho nemůže. Dám příklad: V systému při prohlížení uživatelů mám možnost přidat do přátel uživatele. Takže se při výpisu stránky s možností přidání uživatele do přátel nastaví session['csrf'] a tato hodnota se vloží do linku např adduser.php?id=65&amp;secur=xxxxxxxxxxx. Při přidání tohoto uživatele se opět session['csrf'] změní/unsetne. Nemyslím si, že by někdo v jednom okně editoval profil a v druhém taky. Pak by to mohlo dělat problémy. Pokud se tak stane, systém inteligentně vráti uživatele na stránku s přednastavenými zadanými hodnotami a přepíše CSRF hodnotu. Zárověň uživatele informuje o narušení průběhu, ať akci opakuje. Za tu bezpečnost se tento "krok proti pohodlnosti" imho vyplatí. Znáte lepší řešení?

2008-12-25 13:00:42

Subjektivně tady problém vidím. Například moji uživatelé běžně otevřou seznam diskuzních fór a pak do nových oken otevřou jednotlivá fóra, která je zajímají. Potom po jednom jdou a reagují na tyto diskuze svými příspěvky. ootvírají tedy několik stejných formulářů a ty pak v různém pořadí odesílají. Podobných případů mám na svých webech hodně.

Mé vlastní realizace obdobného nápadu vycházejí z jakéhosi zásobníku těchto csrf, které nemusejí být vybírány v přesném pořadí a mají časově omezenou platnost. Na nic lepšího jsem bohužel zatím nepřišel.

Na tento komentár odpovedal [9] Lukyer
2008-12-25 13:02:18

To Dundee - ty jednotlivé příspěvky našich komentářů mají zvláštní časy, jedna hodina odpoledne není ;)

Na tento komentár odpovedal [8] Dundee
[8] Dundee
2008-12-25 13:06:05

#7 Pavel Šindelka: V Provu (USA) ano :)
Asi bych měl nastavit časové pásmo a nenechávat tam to jejich...

[9] Lukyer
2008-12-25 13:06:29

#6 Pavel Šindelka: V tom pripade by bylo nejjednodussi vygenerovat CSRF retezec pri loginu/navsteve fora a nemenit ho pri odeslani prispevku, ale az pri loginu/necinnosti/vypseni session ... Ale reseni zasobnikem je taky vpohode si myslim. Ono utocnik se nema jak k vygenerovanemu csrf retezci jak dostat, pokud aplikace nema XSS bugy, takze by melo stacit vygenerovat jen jeden retezec.Jeste toto vse propojuji s kontrolou ip adresy, takze pri zmene ip se unsetne cela session ... tudiz by utocnik musel byt jeste z podsite, coz ve vysledku srazi pravdepodobnost k nule ...

Na tento komentár odpovedal [10] ehmo
[10] ehmo
2008-12-25 21:55:34

#9 Lukyer: uff kontrolou ip adresy (ak ju kontrolujes celu, co je vlastne dost jedno) si prave odstrihol uzivatelov aol, verizonu, at&t a par dalsich :) o tomto uz pisal arthur dent http://www.misantrop.info/722555-k-zabezpeceni-session.php a je tam vedena cela diskusia. inak mas v zasade pravdu, aj ked ja som za nasilnu zmenu tokenu pri kazdom formulari osobitne.

napriek tomu ze taketo riesenie trosku zneprijemni zivot ludom ktori maju jednu a tu istu stranku otvorenu viackrat, ochrani ten zvysok. ak uz teda treba, je mozne roznym tokenom priradit casovy limit, resp. este k tomu priradit aj samotnu url formularu, co sa mi javi asi ako najlepsie riesenie. ak totizto budem mat jasne urcene ktory formular aky token pre aky cas, bude sa mi lepsie spravovat cela ochrana, pretoze zistim slabe miesta (napriklad ze uzivatel sice otvara bezne dve okna s rovnakym formularom, ale vyplna len jedno), atd. je vsak dobre, nepodcenovat tuto zranitelnost, ktora moze napachat velmi vela neplechy.

Na tento komentár odpovedal [12] publikační systém wamos
2008-12-25 22:13:41

abych to upresnil - pri loginu si do session['ip'] ulozim ip adresu loginu a pokud se behem relace zmeni, tak uzivatele odhlasim. Tim je osefovano takrka vse, vcetne CSRF. Nevidim v tom problem

Na tento komentár odpovedal [12] publikační systém wamos
2008-12-26 22:17:50

#11 Lukyer: Problém v tom je a to dosti výrazný - jak již psal ehmo (#10 ehmo: ), někteří internetoví poskytovatelé mají změnu IP adresy během jedné relace uživatele jako výchozí vlastnost a tudíž těmto uživatelům znemožníš práci se systémem. U dat získaných o klientovi je možné pro tuto funkci použít např. HTTP_USER_AGENT, který by se neměl měnit - samozřejmě bezpečnost navíc tím není o tolik vyšší jako v případě shodné IP adresy - ovšem neznemožní práci některým uživatelům.

Na tento komentár odpovedal [13] Lukyer
2008-12-28 12:32:14

#12 publikační systém wamos: V rámci jedné relace? To by byl podivný systém, pokaždém requestu reconnectovat? Nevím, neumím si to představit, neznám jediného takového člověka(když už tak mají jiné ip po reconnectu k síti), tudíž je to pro mě zanedbatelné minimum. Kdo bude mít problém, bude si stěžovat, pak to budu považovat za úkol ;) Momentálně neznám lepší řešení(bezpečné) než kontrolu shodnosti ip. Mimochodem tuhle kontrolu ip již provádí imho hodně serverů automaticky, bez ohledu na nějaké skripty php ... Takže to asi opravdu bude minimum lidí ;)

2008-12-28 12:37:25

Až teď jsem koukl na ten link. No, je to zajímavé, dobré vědět, ale pro mě je to pasé, zatím se s takovou situací skoro jistě nesetkám na žádném z projektů. Díky za novou informaci

comments closed