Co je Cross-Site Request Forgery a jak se mu bránit

Je vaše webová aplikace zabezpečená proti Cross-Site Request Forgery (CSRF)? V článku se dozvíte, co znamená CSRF. Vysvětlíme, proč se jedná o bezpečnostní riziko nezávisle na tom, zda vaše formuláře používají metodu GET nebo POST. A dále ukážeme způsob, jak se můžete vůči tomuto problému bránit.

V nedávném článku Přehled útoků na webové aplikace jsme vám představili seznam základních bezpečnostních problémů, se kterými se můžete setkat. Dnes se zaměříme na jeden z nich, a sice na CSRF. Pro pochopení článku budeme vyžadovat alespoň základní znalost formulářů v HTML.

Co je CSRF

CSRF je typ útoku na webovou aplikaci nebo službu. Zkratka CSRF (Cross-Site Request Forgery) znamená „podvržení požadavku mezi různými stránkami“. Někdy se také můžeme setkat i s dalšími termíny jako XSRF, Cross-Site Reference Forgery, Session Riding nebo Confused Deputy attacks.

Co CSRF není

Mnoho lidí spojuje CSRF s XSS (Cross Site Scripting). To ale není správné, protože se jedná o zcela jiné zranitelnosti. Takže ještě jednou: CSRF není XSS!

Popis útoku

Popis CSRF útoku si předvedeme na příkladu. Abychom mohli začít útočit, musíme mít na co. To je také jeden ze základních předpokladů úspěšného CSRF útoku – musíme znát aplikaci, na kterou útočíme.

Pro demonstrační použití nám poslouží fiktivní aplikace webmailu (webového rozhraní pro práci s e-mailem), konkrétně část pro odesílání e-mailu. Ta obsahuje následující formulář:

<form action="poslat" method="get">
  <input type="text" name="komu">
  <input type="text" name="predmet">
  <textarea name="obsah"></textarea>
  <input type="submit" name="Poslat email">
</form> 

Jedná se o jednoduchý formulář, kterým můžeme poslat e-mail. Bude se posílat na adresu serveru složenou ze jména serveru a hodnoty „action“ ve značce „form“ – tedy „http://webma­il/poslat“. Formulář má dále 3 políčka: komu, predmet a obsah. Pojďme na tento formulář zaútočit – poslat e-mail automaticky bez vědomí uživatele.

Využijeme toho, že formulář odesílá své položky metodou GET. Stačí vědět, že jakýkoliv obrázek na webové stránce generuje GET požadavek a jména formulářových prvků i jejich hodnoty jsou v takovém případě součástí URL. Pak si útočník může vložit na své stránce následující kód pro „zobrazení obrázku“. Jako URL obrázku ale vloží GET požadavek, který je totožný s vyplněným a odeslaným formulářem webmailu, na který útočí.

<img src="http://webmail/poslat?komu=nejakyEmail@server&predmet=test&obsah=textemailu"> 

Když si nyní zobrazíme útočníkovu stránku se „zákeřným obrázkem“, tak se odešle e-mail na adresu „nejakyEmail@ser­ver“ bez našeho vědomí. Předpokladem je, že ve chvíli, kdy zobrazujeme útočníkovu stránku, jsme zároveň do webmailu přihlášeni.

Rozšíření útoku na metodu POST

Kdyby server zpracovával jen požadavky poslané metodou POST, útočníkovi k úspěšnému útoku stačí zapnutý JavaScript v prohlížeči oběti a následující kód:

<body onload="document.forms[0].submit();">
  ...
  <form action="http://webmail/poslat" method="post">
    <input type="text" name="komu" value="nejakyEmail@server">
    <input type="text" name="predmet" value="test">
    <textarea name="obsah">obsah emailu</textarea>
  </form> 

Zpracování požadavku na straně serveru je jednou z nejdůležitějších částí aplikace. Aplikace se může rozhodnout, které požadavky přijme a které zahodí. Základním zabezpečením může být přihlášení uživatele a uchovávání informace o přihlášení (session) v cookies prohlížeče (požadavky od nepřihlášených uživatelů bude aplikace ignorovat). Další „zabezpečení“ může být ve zpracovávání požadavků na straně serveru. Například ve skriptovacím jazyce PHP je pravidlem nepoužívat proměnnou $_REQUEST (obsahuje totiž hodnoty z POST, GET i COOKIE). Dalším pravidlem je odesílat a přijímat formuláře výhradně metodou POST místo GET, protože GET požadavek lze jednoduše odeslat např. atributem „src“ v HTML značce „img“, jak jsme si již ukázali.

Další reálné hrozby CSRF

Mezi další reálné útoky může být vytvoření trvalého platebního příkazu na útočníkův bankovní účet z bankovního účtu oběti. Smyšlený formulář na smyšlenou banku může vypadat takto:

<html>
  <body onload="document.forms[0].submit();">
    <form action="http://smyslena-banka/novy-prikaz" method="post">
      <input type="text" name="ucet-prijemce" value="1231231231-3210">
      <input type="text" name="ucet-odesilatele" value="1234567890-0123">
      <input type="text" name="castka" value="1000">
      <input type="text" name="typ-prikazu" value="trvaly">
      <input type="text" name="opakovani" value="mesicni">
    </form>
  </body>
</html> 

Dalším příkladem může být sledování elektronické pošty oběti. Útočník opět musí vědět, jakou webovou aplikaci pro přístup k elektronické poště oběť používá a jak se v ní mění nastavení účtu. Připraví si tedy formulář pro přidání pravidla „automatického přeposílání všech emailů oběti na adresu útočníka“:

<html>
  <body onload="document.forms[0].submit();">
    <form action="http://smysleny-mail-server/nastaveni" method="post">
      <input type="text" name="preposilat-na" value="utocnikuv@email">
      <input type="text" name="preposilat-co" value="vse">
    </form>
  </body>
</html> 

Poslední příklad bude destruktivní. Mějme redakční systém, do kterého můžeme psát články. Jednoduchým požadavkem můžeme smazat veškeré články daného redakčního systému:

<html>
  <body onload="document.forms[0].submit();">
    <form action="http://redakcni-server/sprava-clanku" method="post">
      <input type="text" name="smazat" value="vse">
    </form>
  </body>
</html> 

Mnoho webových aplikací trpělo a stále trpí touto zranitelností. Také Google ještě nedávno trpěl CSRF zranitelností. Bylo možno změnit bez vědomí uživatele používaný jazyk na stránkách vyhledávače. Taková automatická změna jazyka do arabštiny byla docela smutná a je s podivem, že Google danou chybou poměrně dlouho trpěl. Příklad automatické změny preferovaného jazyka vyhledávače na němčinu (již nefunguje):

<img src="http://www.google.com/setprefs?hl=de"> 

Shrnutí faktů o CSRF

  • Automatický útok na webovou aplikaci je možný, pokud oběť navštíví útočníkovu stránku, která odešle předem připravený formulář (např. akce typu „smaž vše“).
  • Je jedno, zda-li se použije metoda POST či GET pro odesílání formulářů. Metoda GET je více zranitelnější, protože pro automatický útok není nutné mít zapnutý JavaScript, viz následující ukázka (automatické odeslání formuláře metodou POST naopak zapnutý JavaScript vyžaduje):

    <img src="http://redakcni-server/sprava-clanku?smazat=vse"> 
  • I když webová aplikace zpracovává požadavky pouze pro přihlášené uživatele, samotný zabezpečovací mechanismus pomocí uložené relace (session) v cookies nás neochrání. Pokud je uživatel přihlášen a zároveň navštíví útočníkovu stránku, cookies se webové aplikaci stejně odešlou. Útok totiž proběhne z prohlížeče oběti (která je přihlášena do aplikace) a odeslání formuláře směřuje do aplikace oběti (do které je oběť přihlášena).
  • Útočník musí znát webovou aplikaci. Musí připravit formulář s akcí, která se provede, až oběť navštíví útočníkovu stránku.
  • Útočník musí oběť nějak přesvědčit, aby navštívila jeho stránku. Asi nejjednodušším příkladem je e-mail s odkazem a textem: „už jsi viděl dnešní vtip na mém blogu?“

Jak se proti CSRF bránit?

Obran proti tomuto útoku bylo popsáno mnoho, ale jen některé jsou účinné.

Neúčinné obrany

Webová aplikace může kontrolovat tzv. HTTP referer, jedná se o hlavičku HTTP protokolu, kterou prohlížeč odesílá společně s požadavkem na danou stránku. Jejím obsahem je URL předchozí stránky. HTTP referer jde ale falšovat a dokonce se nemusí vůbec odesílat (nebo se může ztratit někde cestou – třeba v proxy). V takovém případě nemáme co kontrolovat.

Některé zdroje dokonce radí, aby se kontroloval User-agent řetězec. To je ale úplný nesmysl, protože CSRF útok využívá prohlížeč oběti; User-agent řetězec proto pro přihlášeného uživatele je stejný i během útoku.

Účinná obrana proti CSRF

Základní obranou je používat takzvané „podepsané“ formuláře. Podepsaným formulářem rozumíme formulář s nějakou „tajnou“ hodnotou, kterou generuje server. Vraťme se k našemu příkladu s posíláním e-mailu, do kterého takovou hodnotu přidáme:

<form action="poslat" method="get">
  <input type="text" name="komu">
  <input type="text" name="predmet">
  <textarea name="obsah"></textarea>
  <input type="hidden" name="tajna-hodnota" value="0123456789ABCDEF">
  <input type="submit" name="Poslat email">
</form> 

Serverová část aplikace při generování formuláře vygeneruje i pole s tajnou hodnotou a tu si zapamatuje. Uživatel při odeslání formuláře odesílá i tajnou hodnotu. Serverová část aplikace přijme jen takový formulář, pokud přijatá tajná hodnota odpovídá zapamatované, nedávno vygenerované hodnotě.

Pokud chceme mít tajnou hodnotu pod kontrolou na serveru, tak je nutné se rozhodnout, zda generovat pro každý formulář jinou hodnotu, nebo při přihlášení uživatele vygenerovat jen jednu hodnotu a tu používat po celou dobu platnosti uživatelské relace (session).

Trvalou tajnou hodnotu používá například webmail na Seznamu. Používá k tomu proměnnou „hashId“ odesílanou s každým formulářem. Dříve byla tato hodnota stejná i po novém přihlášení uživatele, nyní se při každém přihlášení generuje hodnota nová.

Pokud si nechceme na straně serveru žádnou tajnou hodnotu pamatovat, můžeme ji také vygenerovat na klientské straně a uložit ji do cookies. Cookies se automaticky odesílají s každým dotazem na server a klientská část aplikace pak musí připojit ke každému odesílanému dotazu na server tajnou hodnotu. Na serverové části aplikace pak stačí zkontrolovat, zda se obě hodnoty shodují. Tento typ ochrany považuji za nejjednodušší na implementaci.

Pro obranu je velmi důležité nedovolit útočníkovi tajnou hodnotu zjistit. Ten ji může zjistit například na nezabezpečené WiFi síti (data jdou jednoduše odposlechnout, např. pomocí nástroje Wireshark) nebo pokud se tajná hodnota vyskytuje v GET požadavku (GET požadavek je vidět v refereru a může být zalogován na různých serverech).

Obrana na straně uživatele

Existuje i nějaká obrana na straně uživatele? Ano, stačí, když se bude chovat „opatrně“. Např. pokud je přihlášen do banky přes webové rozhraní, nebude otevírat žádná další okna nebo záložky ve stejném prohlížeči (nebo ve stejné instanci prohlížeče), dokud se z banky neodhlásí. Pokud totiž otevře stránku obsahující CSRF útok (tedy formulář, který se automaticky odesílá) a není právě přihlášen k webové aplikaci, k žádnému útoku nemůže dojít.

Užitečné nástroje vztahující se k problematice CSRF

  • Tamper Data – jednoduché rozšíření pro Firefox, které umožňuje zobrazit a pozměnit veškeré odesílané formuláře.
  • CSRF Protector – rozšíření pro Firefox ochraňující před některými CSRF útoky.
  • Wireshark – sledování veškerého síťového provozu.

Shrnutí

V článku jsme se pokusili vysvětlit princip CSRF útoku, vyvrátit některé mýty, které okolo něj panují, a předvést způsob, jak se proti němu bránit (ať již na straně vývojáře aplikace nebo na straně uživatele). Pokud se budete držet rad uvedených v článku, neměl by pro vás (resp. pro vaše aplikace) již CSRF být problémem. Nezapomeňte ovšem, že CSRF je jen jedním z mnoha útoků, na které by měly být vaše aplikace připraveny.

Zdroje


Autorem článku je Jan Pejša, vývojář webových aplikací ve společnosti Kerio Technologies s.r.o., která je jedním z hlavních výrobců bezpečnostního internetového softwaru pro malé a středně rozsáhlé sítě, se specializací na síťové firewally a bezpečnost interní firemní komunikace.

Je vaše webová aplikace zabezpečena proti CSRF?

Absolvent ZČU v Plzni. V současné době pracuje jako vývojář webových aplikací ve společnosti Kerio Technologies s.r.o..

Věděli jste, že nám můžete zasílat zprávičky? (Jen pro přihlášené.)

Komentáře: 98

Přehled komentářů

BLEK. Tajná hodnota ve formuláři nefunguje
Martin Hassman clickjacking
pepak Re: clickjacking
Martin Hassman Re: clickjacking
pepak Re: clickjacking
Martin Hassman Re: clickjacking
pepak Re: clickjacking
Martin Hassman Re: clickjacking
pepak Re: clickjacking
Martin Hassman Re: clickjacking
Jakub Vrána Re: clickjacking
Martin Hassman Re: clickjacking
pepak Re: clickjacking
Martin Hassman Re: clickjacking
pepak Re: clickjacking
pepak Re: clickjacking
pepak Re: Tajná hodnota ve formuláři nefunguje
Anonymní Re: Tajná hodnota ve formuláři nefunguje
pepak Re: Tajná hodnota ve formuláři nefunguje
BLEK. Re: Tajná hodnota ve formuláři nefunguje
pepak Re: Tajná hodnota ve formuláři nefunguje
Martin Hassman Re: Tajná hodnota ve formuláři nefunguje
pepak Re: Tajná hodnota ve formuláři nefunguje
BLEK. Re: Tajná hodnota ve formuláři nefunguje
uživatel si přál zůstat v OT: CSRF podle nového TRZ...
Martin Malý Re: OT: CSRF podle nového TRZ...
Pořád v anonymitě Re: OT: CSRF podle nového TRZ...
Martin Malý Re: OT: CSRF podle nového TRZ...
Pořád v anonymitě Re: OT: CSRF podle nového TRZ...
Martin Malý Re: OT: CSRF podle nového TRZ...
vera.pohlova Re: OT: CSRF podle nového TRZ...
Tomas.Brukner AJAX a cookies
Martin Hassman Re: AJAX a cookies
Tomas.Brukner Re: AJAX a cookies
Martin Hassman Re: AJAX a cookies
Tomas.Brukner Re: AJAX a cookies
Anonymní Re: AJAX a cookies
Jakub Vrána Re: AJAX a cookies
prispivatel45421 Re: AJAX a cookies
Jakub Vrána Re: AJAX a cookies
Anonymní Re: AJAX a cookies
danaketh Re: AJAX a cookies
Tomas.Brukner Re: AJAX a cookies
repli Re: AJAX a cookies
vera.pohlova Re: AJAX a cookies
Jan Pejša Re: AJAX a cookies
vera.pohlova Re: AJAX a cookies
Jan Pejša Re: AJAX a cookies
Anonymní RE: Co je Cross-Site Request Forgery a jak se mu bránit
pht RE: Co je Cross-Site Request Forgery a jak se mu bránit
Jan Pejša RE: Co je Cross-Site Request Forgery a jak se mu bránit
pht RE: Co je Cross-Site Request Forgery a jak se mu bránit
Martin Hassman RE: Co je Cross-Site Request Forgery a jak se mu bránit
Jan Pejša RE: Co je Cross-Site Request Forgery a jak se mu bránit
Timy Google
Jakub Vrána Re: Google
Timy Re: Google
Jakub Vrána Re: Google
Jan Pejša Re: Google
Anonymní drobna korektura + dalsi poznamky
Martin Hassman Re: drobna korektura + dalsi poznamky
Jan Pejša Re: drobna korektura + dalsi poznamky
Miloss TYPO (= překlep)
Martin Hassman Re: TYPO (= překlep)
Anonymní Tajna hodnota v cookie
Martin Hassman Re: Tajna hodnota v cookie
Jan Pejša Re: Tajna hodnota v cookie
vera.pohlova Re: Tajna hodnota v cookie
Jan Pejša Re: Tajna hodnota v cookie
vera.pohlova Re: Tajna hodnota v cookie
Jan Pejša Re: Tajna hodnota v cookie
vera.pohlova Re: Tajna hodnota v cookie
Mima Re: Tajna hodnota v cookie
Leoš Ondra Podvrzeni refereru?
Martin Hassman Re: Podvrzeni refereru?
Leoš Ondra Re: Podvrzeni refereru?
Jakub Vrána Re: Podvrzeni refereru?
Martin Straka Re: Podvrzeni refereru?
vera.pohlova Re: Podvrzeni refereru?
Anonymní Re: Podvrzeni refereru?Re: Podvrzeni refereru?Re: Podvrzeni refereru?
Jakub Vrána Re: Podvrzeni refereru?Re: Podvrzeni refereru?Re: Podvrzeni refereru?
vera.pohlova Re: Podvrzeni refereru?
Jakub Vrána Re: Podvrzeni refereru?
vera.pohlova Re: Podvrzeni refereru?
Leoš Ondra Re: Podvrzeni refereru?
vera.pohlova Re: Podvrzeni refereru?
Jakub Vrána Re: Podvrzeni refereru?
vera.pohlova Re: Podvrzeni refereru?
Jakub Vrána Re: Podvrzeni refereru?
vera.pohlova Re: Podvrzeni refereru?
Jakub Vrána Re: Podvrzeni refereru?
nigol A co continuation-based frameworky, např. Seaside?
Jan Pejša Re: A co continuation-based frameworky, např. Seaside?
Filip Jirsák Re: A co continuation-based frameworky, např. Seaside?
nigol Re: A co continuation-based frameworky, např. Seaside?
karmi Díky za precizní článek s výbornými příklady
Martin Hassman Re: Díky za precizní článek s výbornými příklady
David Grudl Ochrana v Nette
Zdroj: https://www.zdrojak.cz/?p=2833