Autor: .cCuMiNn. | 13.4.2011 |
O takto nasazené obraně ovšem všechny zdroje popisující zranitelnost Cross-Site Request Forgery tvrdí, že není vhodná. Málokde se ale již dozvíte, proč tomu tak je, a jak lze tuto ochranu překonat ve chvíli, kdy se s ní ve webové aplikaci setkáte. Tento článek si proto klade za cíl zacelit tuto informační díru a přinést vám chybějící informace.
V úvodu si v krátkosti připomeneme princip CSRF útoku. Tyto útoky jsou založeny na důvěře serveru v HTTP požadavky přicházející od přihlášeného uživatele. Jakmile uživatel odešle HTTP požadavek, rozpozná webový server podle aktuální session (nejčastěji podle hodnoty v cookies), od kterého uživatele tento požadavek přišel a vykoná odpovídající úkon. Je jasné, že některé požadavky by uživatel při plném vědomí nikdy dobrovolně neodeslal. Například by v internetové aukci nekoupil trabanta za milion korun, nebo by v bankovní aplikaci neodeslal požadavek na převod finančních prostředků ve prospěch neznámého bankovního účtu.
Útočníci během tohoto typu útoku proto odeslání podobných HTTP požadavků uživatelům podsouvají například v podobě linků, nebo je odesílájí automaticky pomocí HTML tagů, které požadují externí zdroje (img, iframe, script, apd.). K odeslání požadavků je samozřejmě možné využít také JavaScript. Pokud pak webový prohlížeč oběti odešle takto podstrčený požadavek po kliknutí na odkaz, nebo při návštěvě útočné webové stránky ve chvíli, kdy je uživatel přihlášen k aplikaci, doplní prohlížeč do takového požadavku i odpovídající cookies. Pokud webová aplikace nemá implementovánu ochranu proti CSRF, bude přijatý požadavek zaslaný uživatelem považovat za legitimní a vyřídí jej, aniž by o tom měl zneužitý uživatel tušení. Jako příklad praktického útoku uvedu nastavení přesměrování příchozích zpráv ve webmailu od Seznamu, které bylo s využitím CSRF svého času možné.
No a nyní nastává okamžik se podívát na "zdánlivou" obranu na straně serveru.Každý požadavek, který je webovým prohlížečem odeslán, obsahuje mimojiné HTTP hlavičku Referer. Ta informuje server o URI stránky, která byla zdrojem tohoto požadavku. Snadno by se tedy podle této hodnoty dalo na straně serveru zjistit, zda požadavek přichází skutečně z té "správné" webové stránky a né z webu útočníka.
To zní rozumně a jistě by taková ochrana byla geniálně jednoduchá a účinná. Kde je tedy problém? První problém je v tom, že se v historii již objevily bugy webových prohlížečů, které umožňovaly hodnotu této hlavičky spoofovat, například pomocí objektu XMLHttpRequest, viz. následující příklad:
Toto by ale nebyl zas až takový problém, protože při zveřejnění podobných chyb dojde během relativně krátké doby k nápravě a útočník bez zneužití podobných bugů není schopen hodnotu refereru odesílanou uživatelem zfalšovat. Větší problém ovšem je, že samotné odesílání hodnoty aktuálního URI (včetně všech obsažených proměnných) s každým požadavkem (a to i mimo aktuální doménu) je samo o sobě bezpečnostním problémem, který může způsobit únik důvěrných informací. Z tohoto důvodu je možné odesílání hlavičky Referer zakázat přímo v nastavení webového prohlížeče nebo ji mohou blokovat některé další bezpečnostní programy v uživatelově počítači, například firewall. Mimo to, může být hlavička Referer vypouštěna z komunikace i na straně síťových prvků v rámci bezpečnostní politiky nastavené v organizaci.
V souvislosti s výše uvedeným mohou na stranu webové aplikace (www.example.com) přicházet požadavky, které:
- obsahují správnou hodnotu refereru: (www.example.com/send.php)
- obsahují špatnou hodnotu refereru: (www.attacker.com/atack.php)
- neobsahují v požadavku hlavičku Referer
Co udělat v prvních dvou případech je jasné. Při správné hodnotě v hlavičce požadavek přijmout a při špatné hodnotě jej zahodit. Co však dělat v případě, kdy hlavička Referer v požadavku nedorazí? Pokud takové požadavky aplikace zahodí, pak znemožní práci s aplikací mimo jiné také všem legitimním uživatelům, kteří mají striktněji nastavena bezpečnostní pravidla a tuto hlavičku proto neodesílají. Když ale aplikace požadavky bez hlavičky Referer přijme, otevírá tím cestu útočníkům, protože zajistit, aby webový prohlížeč napadeného uživatele tuto hlavičku neodeslal je poměrně triviální záležitostí.
RFC například zakazuje webovému prohlížeči, aby odesílal hlavičku Referer ze zabezpečených webových stránek (HTTPS), pokud požadavek směřuje na nezabezpečené stránky (HTTP). Útočníkovi proto stačí, aby podvržený odkaz umístil na stránku načítanou protokolem HTTPS a cílem útoku se stala stránka HTTP. Když pak oběť na takto připravený odkaz klikne, může si být útočník jist, že se společně s požadavkem HTTP hlavička Referer neodešle.
Použití zabezepečeného protokolu má pro útočníka ale i jisté nevýhody. Nenápadně jej totiž lze použít pouze u odkazů. v případě, kdy se jedná o útok založený na automatickém odeslání požadavku při načítání externích dat, nebo o data z formulářů odesílaná metodou POST, je uživatel upozorněn na požadavky směřující na nezabezpečené stránky a musí je potvrdit. Ne, že by to uživatel neudělal, ale proč se vydávat touto cestou, když to jde i jinak, ne?
Internet Explorer například ve všech současných verzích hlavičku Referer neodesílá také ve chvíli, kdy je na webovou stránku přecházeno pomocí kódu JavaScriptu, viz. příklad:
Poslení varianty, které zmíním, jsou podobné požadavkům ze zabezpečených webových stránek. Kromě stránek HTTPS neodesílají hlavičku Referer totiž ani webové stránky načítané protokolem FTP nebo FILE. Tyto případy jsou proto vhodné také pro odesílání požadavků pomocí metody POST. Stačí, aby útočník vytvořil HTML dokument například s automaticky odesílaným formulářem a uživatele na něj nasměroval přímo nebo pomocí přesměrování.
FTP://ftp.utocnik.com/atack.html
Hlavičku Referer je pochopitelně možné spoofovat také ve vlastním prohlížeči nebo na vlastním webovém serveru. Tyto metody ale již nemají nic společného s útoky CSRF a proto se jim nebudu věnovat.
Z uvedeného by mělo být patrné, že jedinou správnou ochranou proti útokům CSRF je použití časově omezených jedinečných ticketů. Tyto by se měly stát součástí každého požadavku, a pro útočníka by nemělo být možné zjistit jejich hodnotu bez zneužití jiných zranitelností.