Přejít k navigační liště

Zdroják » JavaScript » Co je Cross-Site Request Forgery a jak se mu bránit

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

Články JavaScript, Různé

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?

Komentáře

Subscribe
Upozornit na
guest
98 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
BLEK.

Tajná hodnota ve formuláři nebude fungovat proti dalšímu útoku — útočník si na své stránce zobrazí jako iframe stránku ze serveru, na kterém chce uživateli ukrást účet, přičemž většinu toho iframe něčím překryje. Napíše tam třeba text "click here to see free porn =>", uživatel do toho klikne, a přitom kliknul do iframe na serveru, na který je přihlášený, do tlačítka, které udělá v jeho účtu nějakou akci. Tajná hodnota ve formuláři bude v tomto případě submitnuta správně.

Tento útok je trochu slabší než CSRF, protože takhle nejdou vkládat automatem položky do formuláře, jde pouze simulovat kliknutí. Ale dá se takhle např. i změnit heslo, stačí, když útočník na své stránce dá do iframe stránku na změnu hesla, přičemž texty překryje něčím, co se tváří jako captcha a přiměje uživatele, aby opsal obsah obrázku do políčka a kliknul na submit.

Správné řešení na obranu je nepoužívat cookies vůbec a autentizační hash vkládat do URL. Aby URL bylo pokaždé jiné a nikdo ho nemohl uhodnout.

Martin Hassman

Takovému útoku se říká clickjacking a asi nejsnazším způsobem (a podle mne lepším než vzdát se cookies), jak mu předejít, je zakázat vkládání své aplikace do iframe (lze vyřešit JavaScriptem).

pepak

Chránit se před málo rozšířeným a slabým útokem (clickjacking) tím, že povolím rozšířené a silné útoky (javascript – skoro všechny útoky na browsery potřebují zapnutý javascript) mi přijde poněkud protismyslné.

Martin Hassman

Pozor na míchání jablek a hrušek, ochrana webové aplikace a ochrana uživatelova prohlížeče jsou nezávislé kroky a každý z nich řeší někdo jiný. Webovou aplikaci si chrání vývojář (obrana před clickjackignem hlídáním paren frame pomocí JavaScriptu je jednoduchá a celkem rozumná cesta), prohlížeč si chrání až uživatel.

pepak

Jenže to nejsou hrušky a jablka, ale vzájemně to spolu souvisí.

Dáváte vývojáři na výběr vlastně jedinou možnou obranu: javascript, který zabrání zobrazení jeho stránky v IFRAME jiného webu. Čili v nejlepším případě přenášíte hrozbu ze sebe na svého uživatele (pokud bude ochrana před CJ účinná, bude vyžadovat zapnutý JS u uživatele a tím ho vystavovat riziku; spíš ta ochrana účinná nebude a přesto vystaví uživatele riziku, takže teď budete ohroženi oba). Mě to úplně v pořádku nepřipadá.

Martin Hassman

Problém je, že neplatí "spíš ta ochrana účinná nebude". Ona skutečně zafunguje (způsob, jak obejít kontrolu vložení stránky do iframu pokud vím nikdy nikdo nevymyslel). Ale je pravda, že to cca procento uživatelů, které si JavaScript vypne, v tomto případě chráněné nebude. Tady hodně záleží na naší aplikaci – pokud JavaScript vyžaduje sama o sobě (což u webových aplikací není neobvyklé), pak bude tato nepokrytá skupina nulová.

pepak

S tou neúčinností jste mě nepochopil; moje chyba, měl jsem to napsat výslovně.

Problém je v tom, že aby ta kontrola před vložením stránky do IFRAME fungovala, tak:

1) Musí být v browseru povolen javascript obecně, což není v zájmu uživatele. Fakticky to znamená, že ta stránka musí být napsaná tak, aby bez javascriptu vůbec nefungovala.

2) Musí browser dovolit změnu Location (což myslím zatím žádný browser nezakazuje, ale dost dobře se na to nemůžete spolehnout už proto, že to může zablokovat třeba nějaká nadstavba).

Osobně si hlavně myslím, že clickjacking je hrubá chyba tvůrců browseru. Co já vím, tak jsou principielně dva způsoby, jak to funguje, a obě by měly být vyloučeny "by design":

1) Útočník překryje ovládací prvek cizího webu svým prvkem a nějak dosáhne toho, že browser kliknutí na útočníkův element přepošle jako kliknutí i na element oběti. To se podle mě nedá označit jinak než za hrubou chybu browseru.

2) Útočník upraví element oběti tak, aby pro uživatele vypadal neškodně a současně lákavě, aby na něj klikl (třeba z input type=submit udělá input type=image s obrázkem imitujícím zajímavý link). Pak jde ovšem o klasický cross site scripting, který by prohlížeč také neměl povolit – nebo se aspoň zeptat, jestli to je OK.

Martin Hassman

clickjacking je hrubá chyba tvůrců browseru

Není. Když by byla chyba na straně prohlížečů, bylo by to dobré a šlo by to vyřešit na úrovni prohlížečů (čili relativně rychle). Clickjacking se ale bude muset řešit (a začal řešit) na úrovni standardů. Je to podobné jako s css exploitem – prohlížeče se chovají správně, byť výsledek je pro uživatele nešťastný – a ťeď babo raď, jak z toho ven.

pepak

Není?

Takže podle vás je v pořádku, když browser při kliknutí na element X pošle kliknutí elementu Y? Je v pořádku, když skript ze stránky X může ovlivnit obsah stránky Y?

Jak z toho ven je celkem triviální:

1) Výrobce browseru upraví svůj produkt tak, aby se kliknutí na prvek X skutečně poslalo jen prvku X.

2) Výrobce browseru upraví svůj produkt tak, aby skript ze stránky X mohl upravovat jedině stránky ze stejné domény.

3) Aby nedošlo k rozbití webů, které jsou (nesmyslně a hloupě) rozhozeny do několika domén s tím, že je vyžadováno mezidoménové skriptování, zavede se buď nějaký standardizovaný META (kterým stránka X řekne prohlížeči, "souhlasím, aby můj obsah měnily skripty s URL odpovídající regularnímu výrazu R") nebo si browser povede uživatelsky definovatelný seznam "povolených cross-scriptů" (tak, jako si dnes browsery vedou seznam povolených cookies nebo seznam povolených popupů). To první je lepší a univerzální, ale nejspíš reálně neprosaditelné, to druhé se může zavést okamžitě.

Martin Hassman

Myslím, že tyhle předpoklady jsou nesprávné (proto nelze hodnotit ani jejich závěry).

Takže podle vás je v pořádku, když browser při kliknutí na element X pošle kliknutí elementu Y?

Můžu vidět nějaký příklad, které tohle skutečně dělá? Clickjacking útoky, které znám, jsou totiž založeny na tom, že uživatel skutečně klikne přímo na element Y.

Je v pořádku, když skript ze stránky X může ovlivnit obsah stránky Y?

Opět bych požádal o příklad, abych se omylem nebavili o něčem, co možná vůbec neexistuje 8-)

Jakub Vrána

Událost kliknutí je v současnosti definovaná tak, že informaci o kliknutí pošle všem elementům, které se na dané pozici nacházejí (dokud někdo z nich nezapne event.cancelBubble). Takže pokud mám div a uvnitř něj span, dostanou informaci oba. To nelze změnit, jinak by přestala fungovat spousta současných aplikací.

Clickjacking navíc může být důmyslnější – zakryje se vše kromě malého místečka cílové stránky a uživatel je motivován k tomu, aby kliknul právě na toto místo (např. formou hry). Uživatel pak skutečně kliká do cílové stránky, takže by navrhovaná opatření nepomohla.

Jediným řešením by bylo zcela zakázat klikání do rámů, to by ale zase ovlivnilo současné aplikace (i když by jich asi zase tak moc nebylo).

Martin Hassman

Jediným řešením by bylo zcela zakázat klikání do rámů

Jediné systematické řešení, které zatím bylo navrženo, je Jakube zakázání vkládání aplikací ho iframe. Ať již na úrovní HTML hlavičky nebo HTTP protokolu. Jiné řešení zřejmě neexistuje. Pokud by tě navržené řešení a diskuse okolo něj zajímala detailně, podívej se na http://lists.whatwg.org/pipermail/whatwg-whatwg.org/2008-September/thread.html#16284.

Pokud to projde, tak si prostě většina aplikací (kromě těch, které chtějí fungovat i jako gadgety) přidá tuhle hlavičku, počká se na nové verze prohlížečů a bude vystaráno. Do té doby nezbývá, než se vložení do iframe bránit JavaScriptem.

pepak

Přesněji řečeno, systematické by bylo _povolovat_ vkládání aplikace do IFRAME (ať už na úrovni HTML nebo HTTP, nebo možná vůbec nejlépe na úrovni nastavení prohlížeče): V bezpečnostních otázkách je zcela nezbytné používat whitelisty, nikoliv blacklisty.

Martin Hassman

Jenže tu máme něco přes 10 let historie. Takové rozhodnutí je z důvodů zpětné kompatibility nereálné.

pepak

Holt si musíme vybrat, jestli chceme řešení reálné a nefunkční nebo řešení nereálné ale funkční. Případně nemusíme mít řešení žádné, to je taky možnost.

pepak

A teď vážně: Ne, zpětné kompatibility bych se nebál. Whitelist tohoto typu by negativně postihl pouze stránky, které legitimně používají IFRAME z cizí domény. Nejsem přesvědčen o tom, že je jich tolik, aby stálo za to je zohledňovat. Snad některé reklamní systémy, možná nějaké špatně napsané Youtube klony. To je myslím tak zhruba všechno.

pepak

To správné řešení ale nic neřeší. Pokud se k té správné URL dokáže proklikat člověk, není moc důvod, proč by se tam nemohl proklikat i robot zobrazující ten IFRAME.

Anonymní

Mám na mysli takové řešení, že uživatel zadá na přihlašovací stránce jméno+heslo. Server je zkontroluje, pokud sedí, tak vygeneruje náhodný řetězec, tento řetězec si sám uloží do tabulky přihlášených uživatelů, k němu uloží čas, aby to nešlo používat libovolně dlouho, a tento řetězec dává do každého URL, které vrátí danému uživateli jako odkaz.

Při přijímání požadavků zase řetězec porovnává a pokud nesedí nebo vypršel čas, tak akci neprovede.

Pokud útočník nezná uživatelovo jméno/heslo a pokud nešmíruje komunikaci mezi serverem a uživatelem (ta se dá navíc zašifrovat v https), tak se k tomu náhodnému parametru v URL nijak nedostane. Pokud ten řetězec v URL někdo vytáhne z historie browseru nebo ze starých proxy logů, tak je mu na nic, protože vypršel jeho čas.

S tímhle parametrem v URL funguje např. xchat nebo mail.centrum.cz a nevidím v tom problém.

pepak

Problém je úplně jednoduchý: Tohle řeší případ, kdy uživatel není na cílovém webu přihlášen. Jenže v takovém případě není clickjacking nebezpečný, protože nepřihlášený uživatel by na tom cílovém webu neměl mít právo udělat nic nebezpečného. Clickjacking je hrozbou pro případy, kdy je uživatel na cílovém webu přihlášen a kdy má práva větší. Jenže když je uživatel přihlášen, tak proběhlo to vaše vygenerování náhodného kódu, jeho zápis do DB a jeho vložení do všech potenciálně nebezpečných URL. Takže stačí zobrazit do IFRAME hlavní stránku cílového webu a provést clickjack, kterým se uživatel přesune na cílové URL (teď už unikátní). Druhý clickjack pak provede žádanou akci. Clickjackující útočník vůbec nepotřebuje to unikátní ID znát, stačí mu, že ho zná ten uživatel, respektive že server si ho použije sám na základě vědomí, že s ním pracuje ten uživatel!

BLEK.

Jo, tohle by šlo v případě, že má uživatel zapnuto automatické vyplňování hesel. Takže ještě by server musel vypnout toto, čímž by zase uživateli znepříjemnil přihlášení.

pepak

Automatické (ani jakékoliv jiné) vyplňování hesel s tím nemá vůbec nic společného. Kromě toho to server nemůže nijak ovlivnit, i kdyby chtěl.

Prostě si představte, že jste přihlášený do Googlu na svůj Gmail účet. No a teď vás nějaká stránka přesvědčí, že ve své poštovní schránce máte kliknout na "delete all", a v zápětí vás přesvědčí, že máte kliknout na "yes, really". Google může mít zabezpečení jaké chce, pokud jste do něj přihlášen a útočící stránce se podaří vás přesvědčit, ať na ty linky kliknete, tak prostě nemůže nijak zabránit tomu, abyste si svou poštu nesmazal.

A o tom právě je celý clickjacking: že existuje způsob, jak uživatele přesvědčit, aby udělal akci, kterou by normálně vůbec neudělal. Nemá to celkem nic společného se zabezpečením napadávaného webu, který tomu dost dobře nemůže zabránit.

Martin Hassman

Nemá to celkem nic společného se zabezpečením napadávaného webu, který tomu dost dobře nemůže zabránit.

Až na tu javascriptovou kontrolu na vložení do iframe, která je celkem spolehlivá 8-)

pepak

Ano, za cenu toho, že riziko přesune na uživatele.

Plus si nejsem až tak 100% jistý, že jediným způsobem, jak použít clickjacking, je IFRAME. Předpokládám, že přinejmenším přes OBJECT by to mělo jít taky, a nebyl bych až tak moc překvapen, kdyby se clickjackovací funkce objevily i pro samostatná okna (přes window.open si otevřít nové okno, šikovně ho namaskovat a nechat uživatele, ať si do toho klikne).

BLEK.

V okamžiku, kdy je to URL, které zobrazí tlačítko "delete email", tajné — t.j. v tom URL je obsažen tajný hash, tak tě žádný útočník nemůže přesvědčit, abys na to kliknul — když útočník nezná URL, na které se v tom iframe má odkázat, tak ten iframe nevyrobí.

Šlo by to tak, že ti útočník zobrazí titulní stránku a donutí tě kliknout na "login" (a předpokládá, že máš zaplé samovyplňování hesla) a pak na "delete email".

uživatel si přál zůstat v

Páni poslanci už přeci otázku CSRF, XSS a vůbec všeho vyřešili v návrhu nového trestního zakoníku za nás… ;-)

§ 228:
(1) Kdo překoná bezpečnostní opatření, a tím neoprávněně získá přístup k počítačovému systému nebo k jeho části, bude potrestán odnětím svobody až na jeden rok, zákazem činnosti nebo propadnutím věci nebo jiné majetkové hodnoty. …

§ 229
(1) Kdo v úmyslu spáchat … trestný čin neoprávněného přístupu k počítačovému systému a nosiči informací podle § 228 … vyrobí, uvede do oběhu, doveze, vyveze, proveze, nabízí, zprostředkuje, prodá nebo jinak zpřístupní, sobě nebo jinému opatří nebo přechovává
a. … postup, nástroj nebo jakýkoli jiný prostředek, včetně počítačového programu, vytvořený nebo přizpůsobený k neoprávněnému přístupu do sítě elektronických komunikací, k počítačovému systému nebo k jeho části, nebo
b.počítačové heslo, přístupový kód, data, postup nebo jakýkoli jiný podobný prostředek, pomocí něhož lze získat přístup k počítačového systému nebo jeho části,
bude potrestán odnětím svobody až na jeden rok, propadnutím věci nebo jiné majetkové hodnoty nebo zákazem činnosti.

-> takže autor článku rok natvrdo ("vytvoření trvalého platebního příkazu na útočníkův bankovní účet", "příklad bude destruktivní", odkaz na wireshark => úmysl je zde celkem zřejmý), my ostatní, co to čteme, bysme mohli vyváznout jen s podmínkou… ;-)

Já vím, ironie, nadsázka a tak vůbec, ale nedá mi to a demonstruju na tom častou chybu podobných právních výkladů. Totiž zákon praví: "Kdo v úmyslu spáchat to a to udělá to či ono" – a tady narážíte, protože autorovi neprokážete úmysl spáchat podobné činy. :)

Pořád v anonymitě

Přesně tak: ironie, nadsázka a tak vůbec (pochopeno správně)
Nicméně je dobré, mít na paměti existenci podobných obludností.
Ano: Úmysl je v naprosté většině případů prakticky neprokazatelný. (autora tedy necháme jít s podmínkou ;-)
Ale: § 228 žádný úmysl nezmiňuje. Takže CSRF (bude) zakázáno zákonem a basta! ;-)

Martin Malý

Správně! A jak to zákon zakáže, tak končí sranda! :) Ještě bych tam vložil paragraf "Ohrožení dat uchovávaných v systému elektronického uchování dat", a to nějak takhle:

1. Kdo si zvolí heslo, které je rovno jeho datu narození, jménu manželky, psa, kočky, oblíbeného sportovního klubu či podobné, bude potrestán odnětím svobody na 6 měsíců nebo zákazem práce s výpočetní technikou na pět let.

2. Výjimečný trest dostane ten, kdo zvolí heslo "12345" nebo několik stejných znaků.

A bude! :)

Pořád v anonymitě

Mám lepší řešení: KAŽDÝ by na základě presumce viny dostal př narození 80 let podmínečně. Každý přeci porošuje nějaké zákony, jen státní úředník není vždy na místě, aby to stačil postihnout…

Prevence musí bejt!

Martin Malý

To je, možná, přehnané, stačilo by uzákonit, že vlastnictví počítače jednoznačně prokazuje záměr páchat počítačovou kriminalitu, a všechny tyhle clickjacky a dětská pornografie by byly jednou provždy vymýceny. Beztak to poctivýmu pracujícímu k ničemu není!

vera.pohlova

Správně! Já bych všechny ty internety, clickjackingy a csrf zakázala …

Tomas.Brukner

Co se týče uložení "tajné hodnoty" do cookies, tak to není dobrý nápad – cookies se v javascriptu dají číst, a proto bych se bál toho, že se k té hodnotě útočník dostane. V tomhle případě doporučuji ukládat tu hodnotu třeba do PHPSession – přeci jenom většina formulářů, které by mělo smysl zneužít, se používají až po přihlášení uživatele – a tam už se nějaká identifikace uživatele používá, takže uložení na straně serveru je většinou snadno možné. (Případně je možné hodnotu cookie nějak šifrovat, aby jen server znal skutečnou tajnou hodnotu a nedala se zjistit pouze z hodnoty cookie.)

Další problém je s technologií AJAX – tam je potřeba toto řešit také, jelikož se jedná v principu o to samé a lze to napadnout úplně stejným způsobem.

Ad ochrana:
U uživatele je myslím rozumné používat "anonymní mód" – viz http://zdrojak.root.cz/zpravicky/google-chrome-vicenasobne-prihlaseni/.
Na straně stránek to je mnohem těžší, tam je nejspíš nejrozumnější celkem náročná implementace nějakého jednorázového tunelu nad autorizací v Javascriptu (v tom případě by web měl být kompletně napsaný nad technologií AJAX, aby všechna data šla přes tento tunel); toto řešení je imunní vůči CSRF (tunel si posílá nějakou jednorázovou hodnotu, která se mění pro každý další dotaz na server) i proti Clickjackingu – při otevření iframu se znovu načte stránka, a tudíž nebude uživatel autorizován, jelikož bude autorizován jen v rámci tunelu na původní stránce.
Bohužel formuláře bez autorizace nelze proti Clickjackingu efektivně bránit, maximálně v Javascriptu zabránit, aby byl web načten v iframu.

Martin Hassman

Co se týče uložení „tajné hodnoty“ do cookies, tak to není dobrý nápad – cookies se v javascriptu dají číst

Záleží na tom, jak moc jste si jistý, že je vaše aplikace odolná vůči XSS. Pokud se XSS nebojíte (myšleno oprávněně, protože vstupy pečlivě kontrolujete), tak lze cookies bez problémů použít. Ale je to skutečně o potenciální riziko navíc (důležité je, že je jen „potenciální“).

Tomas.Brukner

Ano, riziko to je potenciální – jednak to lze zneužít nějakou další zranitelností přes XSS, a druhak by to mohlo jít ještě takhle (tímto postupem si nejsem jistý, jenom mě napadá) – při načtění iframe na útočníkově stránce by se teoreticky dalo přes DOM dostat ke cookies stránky v iframe – nejsem expert na rozdíl implementace Javascriptu v prohlížečích, ale myslím si, že schopný útočník by to mohl zneužít jestli to je možné.

Martin Hassman

při načtění iframe na útočníkově stránce by se teoreticky dalo přes DOM dostat ke cookies stránky v iframe

Ne, tohle skutečně nejde, to by byla velká bezpečnostní bota v návrhu samotných cookies.

Tomas.Brukner

Jediné štěstí – vím jaká kouzla jsou v JavaScriptu možná, a proto si člověk nejdřív musí vyzkoušet, jestli to či ono funguje nebo ne (i v souvislosti s útoky).

Anonymní

v IE6 toho šlo… šlo např. javascriptem ovládat vnořený frame, takže jste mohli otevřít stránku bankovního ústavu a je-li uživatel shodou okolností přihlášen v jiném okně, tak s tímto oknem třeba vyplnit formulář a odeslat.

Jakub Vrána

Nic takového možné nebylo, IE6 kontroluje přístup k vnořeným rámům stejně jako všechny ostatní prohlížeče (pokud se liší doména rámu, žádný přístup nepovolí).

Přinejmenším takový výrok nelze napsat bez újmy na obecnosti – pokud máte na mysli nějaké konkrétní neopravené verze IE6 nebo nějaký speciální způsob využívající jiné bezpečnostní chyby tohoto prohlížeče, tak je potřeba to napsat. Jinak je takový výrok obyčejný FUD.

prispivatel45421

Prehliadac IE6 sa opyta, ci dovolujete cross-domain scripting. Vacsina ludi pri takom niecom zarucene odpovie "Ano". Potom mozete kludne pristupovat AJAXom aj k inej domene.

Jakub Vrána

Aktualizovaný Internet Explorer 6 ve výchozí konfiguraci tuto otázku nepokládá a operaci rovnou zamítne.

Anonymní

Je pravda, ze som ho neaktualizoval, ale som mal zasa len strednu (tj. nie vysoku) uroven zabezpecenia na testovanom PC. Vtedy mi neslo o nic zle, len som chcel pomocou AJAXu navstivit stranku z inej domeny. Skusal som to cez iframe a ako som mohol, neslo to. Nastastie (nanestastie?) sa az IE opytal, ze ci to dovolim, tak som zistil, kde robim chybu a ze to moze byt nebezpecne.

danaketh

Tak ta hodnota v cookie by se dala ukládat jako posolený hash.

Tomas.Brukner

Opravdu dobrý nápad, tohle je rozumné řešení a relativně snadné na implementaci (IMHO).

repli

Článek právě pojednává o tom, že ani formuláře po přihlášení nejsou v bezpečí a z jiných stránek je může autor zneužít (pokud zná strukturu formuláře).

Pokud odešle formulář, automaticky se použije i hodnota PHPSession, tedy bude přihlášen a kód se provede.

vera.pohlova

Já jsem teda jenom obyčejná důchodkyně a těmhletěm internetům vůbec nerozumím … ale jste si vědom toho že ID té PHP session se většinou ukládá taky do cookie, a z bezpečnostního hlediska v tom tedy není výrazný rozdíl? Pokud vaše stránky budou náchylné na XSS, tak je jedno jestli to uděláte tak nebo tak – přes JS se dostanete k oběma.

Také jsem zcela nepochopila čeho chcete dosáhnout tím šifrováním, ale třeba mi to vysvětlíte. A AJAX na pozadí také používá POST / GET požadavky, takže nepochybuji že to také půjde prolomit – je to sice složitější na implementaci, ale určitě to půjde.

vera.pohlova

Šifrováním samotné hodnoty cookie se nedocílí vůbec ničeho, protože ono úplně stačí odposlechnout tu šifrovanou hodnotu. Sledujte se mnou:

Standardní request:

1) server vygeneruje tajnou hodnotu cookie "A" a zašifruje ji čímž získá hodnotu "B" kterou pošle klientovi
2) klient vezme hodnotu "B" a odešle ji společně s requestem (například ji vloží do formuláře)
3) server vezme zašifrovanou hodnotu cookie, dešifruje a porovná

S odposlechem:

1) server vygeneruje tajnou hodnotu cookie "A" a zašifruje ji, atd. …
2) zlý hacker odposlechne zašifrovanou hodnotu cookie a uloží si ji
3) zlý hacker vytvoří potřebný request (formulář) a přiměje klienta aby ho odeslal, přičemž v requestu použije odposlechnutou šifrovanou hodnotu
4) server přijme request, a bez problémů ho zpracuje protože obsahuje "bezpečnou" tajnou hodnotu

A včil jsme v piči – celé to právě popsané šifrování cookie je nedomyšlené a nefunguje. Aby to fungovalo tak by klient nesměl posílat zpět tu samou šifrovanou hodnotu jako dostal, ale musel by ji nějak upravit – například dešifrovat a zašifrovat jiným heslem, které by ale musel znát server aby výsledek mohl dešifrovat a zkontrolovat.

Ne že by takové JS šifrování neexistovalo, ale vyžaduje to další věci – například bezpečnou výměnu klíčů. Ale možná existuje nějaká ďábelsky chytrá finta která to řeší. Daleko jednodušší mi ale přijde prohnat to přes SSL a nešaškovat s nějakým custom developed šifrováním.

A teď mne omluvte, jdu se dívat na mexickou telenovelu.

Anonymní

Clanek popisuje, ze utok CSRF se tyka pouze operaci typu "write". Neni mozne pomoci CSRF "precist" neco co bych cist nemel, napr. vypis z uctu, jelikoz je uzivatel prave prihlasen do banky?

pht

Kurnik, nepral jsem si. :)

pht

Plati to i o obrazkach, ktere ziskam pres image.src = xsrf_adresa ? Nelze s tim obejktem image pak udelat neco, ze se ten obrazek dostane do nepovolanych rukou?

Martin Hassman

Tím jen obrázek může zobrazit webová stránka uživateli, ale ještě se nedostal k útočníkovi a ten nemá jak k obsahu obrázku přistoupit. Takový canvas, který umožňuje přistupovat k obrázkům (a třeba i jejich obsah někam odeslat) může přistupovat pouze k obrázkům ze stejné domény, z tohodle pohledu bezpečné.

Timy

Jestli jsem to správně pochopil, tak třeba i takové odhlášení Googlu trpí tímto problémem, protože stačí cinknout na tuhle adresu http://www.google.cz/accounts/ClearSID a Google vás odhlásí. Samozřejmě to funguje i s pouhým obrázkem: http://jdem.cz/ah4n4 Správné řešení by tedy bylo chtít u odhlášení nějaký náhodně vygenerovaný hash uložený v cookies? Třeba google.cz/accounts/ClearSID?hash=123456 a pak kontrolovat, zda je hash v cookie stejný jak v GET?

Jakub Vrána

Odhlášení je akce, která nepochybně změní stav aplikace, takže by měla být provedena metodou POST. Alespoň já jsem to tak v phpMinAdminu udělal.

Timy

Podle článku to přece nepomůže, když jsem schopný automaticky odeslat formulář metodou POST přes Javascript. Nebo je v tom nějaký další fígl? :-)

Jakub Vrána

Finta je v tom, že odhlášení je stejně jako ostatní POST formuláře chráněno proti CSRF pomocí tokenu.

Anonymní

Super clanek, vse dobre vysvetlene

Ve formulari pod "Rozšíření útoku na metodu POST" ma asi byt method="post" (get by tam asi mohlo byt, pokud by utocnik vedel, ze serverova aplikace je napsana v PHP a pouziva $_REQUEST)

Ruby on Rails k ochrane pred CSRF take pouzivaji vygenerovanou hodnotu v hidden poli formularu, a session data ukladaji zasifrovana do cookies. Pry to docela funguje, ovsem az na zranitelnost proti jinemu typu utoku, tzv, reply attack (viz treba http://www.ruby-forum.com/topic/102147#new), ovsem nazory na zavaznost tohoto typu utoku se ruzni

Jeste co se XSS (a potazmo vlastne i CSRF), tyce, vedeli jste, ze PHPkova funkce setcookie() prijama od verze 5.2. parametr httponly, ktery zabranuje cteni obsahu cookie pomici javascriptu? (http://cz.php.net/manual/en/function.setcookie.php)

Martin Hassman

Tem POST jsem opravil, děkujeme.

httonly je dobrá věc, ale funguje, myslím, zatím jen v IE a Firefoxu. Ostatní prohlížeče přístup povolí i k takovému cookies; nicméně to nijak nebrání tomu nastavovat httponly jako prevenci v každém případě.

Miloss

Rozšíření útoku na metodu POST
<form action="http://webmail/poslat" method="get">

Předpokládám že v bloku textu ukazující post útok by měla být metod="post"

Martin Hassman

Určitě, viz výše.

Anonymní

Pan Pejsa, mozete objasnit ako bola ta idea s tajnou hodnotou v Cookies myslena? V kombinacii s per-session hashId spomenutou o odstavec vyssie tato ochrana predsa nedava ziaden zmysel… (k utocnikovmu CSRF submitu browser automaticky prilozi cookie, takze utocnik nema co riesit a nepotrebuje ziadne XSS). Alebo mi nieco unika? Vdaka!

Martin Hassman

V článku se psalo o možnosti kromě uložení "tajné hodnoty" do formuláře ji uložit i do cookies. Pak to samozřejmě funguje. Důvodem bylo, aby se pro porovnání nemusela tajná hodnota uchovávat (pro účely porovnání) na serveru.

vera.pohlova

IMHO je lepší generovat tu tajnou hodnotu už na serveru a ne až na klientovi – například pokud vaše aplikace JS nevyžaduje tak proč ho tam zbytečně tahat, že? A implementačně je to skoro stejné, nijak výrazně se to neliší – pár řádek PHP kódu.

Nehledě na to že cookie se dá využít i elegantněji – na serveru si vygeneruji hodnotu, uložím si ji a pošlu ji uživateli jako cookie. Díky tomu on mi ji při každém requestu automaticky pošle a já si ji mohu porovnat se svojí uloženou hodnotou. Výhoda je v tom že nemusím do úmoru tu hodnotu vypisovat do "hidden" položek všech formulářů (a funguje to dokonce i pro GET requesty aniž bych musela tu tajnou hodnotu uvádět v URL).

Teda, původně mne všechny ty internety jenom otravovaly, ale já jim snad nakonec ještě přijdu na chuť …

vera.pohlova

Máte pravdu, mladíku, chybička se vloudila. Samozřejmě nestačí mít tu tajnou hodnotu uloženou jen v cookie – neuvědomila jsem si že cookie se odesílají podle cíle requestu, nikoliv dle zdroje. Takže pokud se odesílá podvržený request z cizího počítače na můj server, vezmou se cookie z mého serveru. Takže "hidden" položky ve formuláři je skutečně nutno použít …

Ale snad mne omlouvá pozdní hodina a skutečnost že jsem byla rozrušená z pořadu "Volejte věštce" – ta ježibaba ve studiu vážně umí věštit budoucnost!

vera.pohlova

Nezapomínejte mladíku že útočníkův request jde sice prohlížeče uživatele, ale z jiné domény, a tudíž nedostane cookie s tajnou hodnotou kterou si uložila původní stránka. Sleduj se mnou:

1) server http://www.jezevcik.com vygeneruje tajnou hodnotu "x" a pošle ji klientovi
2) útočník na server http://www.vzteklina.com umístí skript který na server pošle POST request "delete-all", a přiměje uživatele aby ho spustil (jedno jak)
3) útočníkův skript se ale spouští na http://www.vzteklina.com a tudíž nedostane cookies nastavené pro http://www.jezevcik.com
4) server http://www.jezevcik.com si zkontroluje hodnotu "x" a má vyhráno

Mima

Paní Pohlová,

asi jsem taky něco nepochopil. Pokud útočník na http://www.vzteklina.com použije k útoku IFRAME z domény http://www.jezevcik.com, kde lstivě skryje to, že se jedná o stránku "chcete smazat všechny své e-maily" a donutí (jedno jak) uživatele kliknout na "ano"…

…pak server jezevcik.com dostane:
1. tajny hash ktery si sam vygeneroval
2. tajnou cookie, kterou si sam nastavil

Podle mého není v případě použití IFRAME žádný rozdíl mezi tím, jak uživatel server jezevcik.com používá normálně a jak ho používá, aniž by o tom věděl. V tom případě je však jakákoliv ochrana tohoto typu neúčinná.

A druhá věc k Vašemu příkladu – POST se pošle na jezevcik.com (jinak by to nebyl útok na jezevcik.com) a ten svou cookie, kterou si v bodě jedna nastavil, samozřejmě obdrží.

Leoš Ondra

"HTTP referer jde ale falšovat"

"protože CSRF útok využívá prohlížeč oběti" (v casti o kontole user-agent)

Jak jdou tyhle dve veci dohromady? Jak je mozne zfalsovat referer na strane klienta, tedy prohlizece obeti? Diky, Leo

Martin Hassman

V tomhle případě se jedná o nezávislé odstavce. Není třeba nic dávat dohromady.

Leoš Ondra

Fajn, a jak je tedy mozne zfalsovat referer abych uskutecnil CSRF? Leo

Jakub Vrána

Falšování HTTP refereru v souvislosti s CSRF samozřejmě nedává smysl (bavíme-li se o aktualizovaných prohlížečích). Snažil jsem se to vysvětlit už Rastislavu Turkovi na jeho přednášce na WebExpu a jsem rád, že nejsem jediný, kdo si to uvědomuje…

Problém je v tom, že se na přítomnost Refereru nedá spolehnout, protože např. firewally ho odstraňují. Kvůli tomu bychom museli povolit provedení operace i bez Refereru, což by dovolilo útočit na uživatele se zapnutým firewallem.

Martin Straka

Neda se nez souhlasit, taky nechapu proc to porad lide opakuji ("referer se da falsovat").

Plus (pro podporu nazoru o nesmyslnosti zalozeni obrany proti CSRF na kontrole refereru) pridam, ze je mozne vytvorit v prohlizeci pozadavek uplne bez refereru a to pro POST i GET metodu

vera.pohlova

Lidi to opakují protože nepřemýšlejí. Někde jednou slyšeli že http referer se dá zfalšovat, všichni s tím evidentně souhlasili, takže to nutně musí být pravda, ne? To že to bylo v úplně jiném kontextu, a že tady to evidentně neplatí, jim jaksi uniká.

Anonymní

A vy jste si to nakonec nevysvětlili? :-)

Jakub Vrána

Bohužel ne. Mám pocit, že cílem pana Turka je šířit mezi lidmi strach a nikoliv zvyšovat bezpečnostní povědomí. Takže když si někde přečte, že v jakési prehistorické verzi některého prohlížeče šlo podvrhnout Referer, tak to zobecní a na přednášce řekne, že lze podvrhnout Referer. To se ale prostě bez újmy na obecnosti říct nedá.

vera.pohlova

Tak původně jsem si myslela že referer přes JS jednoduše spoofovat nepůjde, ale vypadá to že to jde – viz například:

http://www.cgisecurity.com/lib/XmlHTTPRequest.shtml

Je to sice z roku 2005 ale týká se to IE 6, což je stále ještě relativně dost rozšířený browser.

Takže pokud někdo bude chtít, nedá mu asi velkou námahu složit si obdobným způsobem libovolný request s libovolným refererem.

Jakub Vrána

V aktuální verzi IE6 se tato chyba již neprojevuje.

vera.pohlova

Aha, nemohla jsem to odzkoušet protože ačkoliv jsem důchodkyně tak používám Linux. Každopádně to vypadá že tvrzení "v tomto případě referer falšovat nejde je mylné" – další argument proti referer-based ochraně proti CSRF (k již zmíněným problémům s firewally).

Leoš Ondra

"další argument proti referer-based ochraně proti CSRF (k již zmíněným problémům s firewally)."

A jak konkretne by v tomto pripade slo podle Vas podvrzeni refereru Javascriptem zneuzit k CSFR (predpokladejme, ze uzivatel / obet utoku ma ten nezabezpeceny IE6).

Problem s firewally je opacny – neumozni CSRF, pokud referer vyzaduji a delam jeho kontrolu tak omezim opravneneho uzivatele, ale neumoznim utok.

Leo

vera.pohlova

Pokud používáte kontrolu http referera jako ochranu před CSRF, a útočník dokáže využít nějakou chybu v browseru aby ho podvrhnul (viz. výše uvedená – byť v aktuálních verzích IE již opravená, ale hodně lidí IE 6 určitě ještě používá) tak vaši ochranu dokáže překonat. Když se to spojí ještě s problémy s firewally, tak se referer-based ochrana jeví jako nepoužitelná. Cílem ochrany by totiž mělo být:

(1) znemožnit daný typ útoku
(2) neznemožnit fungování aplikace

Při srovnání s tokenem to prostě vychází výrazně lépe pro token – je spolehlivý a bez negativních efektů.

Jakub Vrána

Za prvé je ta chyba opravená i v aktuální verzi IE 6. I tento prohlížeč byl aktualizován, především právě o bezpečnostní záplaty.

A navíc Leoš Ondra správně poukázal na to, že odkázaný útok se pro CSRF nedá použít, protože CSRF je založeno na transparentním poslání cookie, ke kterému při tomto útoku nedojde.

Takže i když souhlasím, že Referer se pro obranu proti CSRF použít nedá (protože ho firewally filtrují), tento příspěvek je poněkud mimo.

vera.pohlova

Ale já jsem netvrdila že to v aktuální verzi IE6 není opravené! Já tvrdím že hodně lidí používá starší prohlížeče nebo neaktualizovanou verzi IE6, a u těch to podvrhnout půjde.

Nerozumím jak s tím souvisí to že CSRF je založeno na transparentním posílání cookie – to je samozřejmě v podstatě pravda, ale jak to souvisí s obcházením kontroly referera?

Jakub Vrána

Jak se dá zjistit, kolik lidí používá neaktualizované IE6, když tvrdíte, že jich je hodně?

Odkázaným útokem se dá podvrhnout Referer, nepošle se ale cookie. CSRF tímto útokem tedy provést nelze.

vera.pohlova

Uznávám že detailní a průkaznou statistiku kolik lidí používá neaktualizovaný IE6 nemám – nicméně IE6 používá aktuálně cca 25% lidí a kdyby jenom 10% bylo neaktualizovaných (a tedy zranitelných výše uvedenou chybou) tak pro 2.5% lidí ochrana nefunguje.

Každopádně shodneme se že token je řádově lepší ochrana před CSRF než kontrola refereru?

Jakub Vrána

Ano, to nikdo nerozporuje. Jen je potřeba se vyjadřovat přesně a nesměšovat "Referer lze podvrhnout" s principem CSRF. Protože když už někdo Referer podvrhne, tak zároveň nepodvrhne cookie.

nigol

Já myslím, že ty jsou před spoustou těchto útoků chráněné už z principu. V Seaside to funguje zhruba takto… Každá session dostane vygenerovaný hash, který se předává v URL a navíc každá akce má přiřazený opět hash, který se ovšem po každé vygenerované akci mění. Tzn. že například link na akci "delete" má v jeden okamžik hodnotu "iOvfrbZo", ale stačí provést jakoukoliv akci nebo refresh stránky a původní hash už neplatí, ale akce "delete" má nyní hodnotu třeba "TCXdQyWZ". A samozřejmě tahle akce platí jen pro tu konkrétní session.
Myslím, že to je zabezpečení víc než slušné.

Filip Jirsák

„a funguje pak taková aplikace ve více záložkách?“

Ano, funguje. Onen předávaný hash akce totiž neidentifikuje akci samotnou, ale jejího předka (alespoň takhle to má Apache Cocoon). Na serveru pak nemusíte mít seznam navazujících akcí, ale může to být strom – pokud z jednoho místa otevřete víc záložek, má odpovídající místo ve stromu víc potomků.

nigol

Ono jsem to možná špatně vysvětlil. V Seaside jsou i ty jednotlivé stránky adresovány pomocí těch action hashů. Takže pokud máme například aplikaci na adrese "www.apl.cz" tak po zadání té adresy do prohlížeče se vygeneruje například "www.apl.cz/?_s=RfbsExbGPszyseST&_k=CqAJIouj" a pokud otevřeme novou záložku opět s adresou "www.apl.cz", dostaneme "?_s=JmSGvKrMLqzkmpAY&_k=ZhPyTUdi". Vizuálně i funkčně to vypadá stejně, ovšem v praxi 2 rozdílné instance té aplikace, tudíž problém nastat nemůže.
Pokud bychom otevřeli první záložku a měli adresu "www.apl.cz/?_s=RfbsExbGPszyseST&_k=CqAJIouj", otevřeli druhou záložku a přesně tam zkopírovali tu adresu, zobrazilo by se nám to samé a dokonce adresa by zůstala stejná. Pokud bychom na té stránce kliknuli na akci "delete" (která by měla na obou stránkách stejný hash), v obou případech by se akce provedla (díky mechanismu cache, uchovávající posledně použité požadavky), ale poté by byla v každé záložce jiná adresa, protože každa záložka by vygenerovala nový request nezávisle na sobě. V každé takto vyrenderované stránce by samozřejmě odkazy (i když ukazující třeba na stejné akce) měly už naprosto jiné action hashe.

karmi

Díky za výborný článek a díky zejména za výborné příklady.

(Přeposílám kolegovi, který se mne dneska párkrát ptal, proč nás pořád tak trápí ten ActionController::InvalidAuthenticityToken :)

karmi

Martin Hassman

Není zač. Přeposílám poděkování do Plzně.

David Grudl

Pokud používáte Nette Framework,
můžete aktivovat ochranu před CSRF metodou addProtection(). V praxi to
může vypadat nějak takto:

// jednoduchý formulář na změnu emailové adresy
$form = new Form;
$form->addText('email', 'E-mail:')
        ->addRule(Form::FILLED, 'Please enter new email.')
        ->addRule(Form::EMAIL, 'The entered email is not valid.');

$form->addSubmit('save', 'Save');

$form->addProtection('Please submit this form again 
        (security token has expired).');

Zprava v metodě addProtection je volitelná a zobrazí se uživateli tehdy, pokud
odesílání kvůli CSRF ochraně selže. Například když token stačil vyexpirovat.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.