Podpora SameSite cookie v Nette a CSRF
- David Grudl
- Nette Core | 8227
Doplnil jsem do Nette (konkrétně do nette/http) podporu pro SameSite cookie, což je první systémová obrana proti CSRF. CSRF útok spočívá v tom, že útočník vyláká uživatele webu A na svou stránku na webu B, která nepozorovaně provádí v prohlížeči uživatele a tedy pod jeho identitou nějakou skrytou nepříjemnou činnost na webu A.
Popis najdete třeba zde:
SameSite cookie mají za cíl nahradit $form->addProtection()
nebo Nextras Secured Links a nevyžadují nastartování
session.
Ačkoliv se podpora pro SameSite cookie objevila v prohlížečích teprve nedávno, podle Caniuse ji už najdete v 68 % zařízení, což ještě stoupne za měsíc po vydání iOS 12.
(Zároveň je potřeba dodat, že značné procento zařízení je nepodporuje, takže addProtection & spol. zatím opustit nelze.)
Jak vypadá podpora v Nette 2.4 (2018–09–18)?
Tak jednak přibyl nový parametr $sameSite
v metodě
Nette\Http\Response::setCookie()
, který může nabývat hodnot
'Lax'
, 'Strict'
nebo null
. Ale to není
tak zajímavé.
Daleko užitečnější ovšem je posílání session ID s nastavením
Tohle se
v praxi ukázalo jako problematické kvůli nestandardní implementaci
v Safari pro iOS. (info)sameSite: Lax
. Lax říká, že pokud se na web odešle POST
formulář z jiné domény, nestane se tak pod aktuálně přihlášeným
uživatelem. Jednoduše v HTTP požadavku bude chybět cookie se session ID
(týká se to i AJAXových požadavků, iframe apod).
Ochranu spustíte konfigurací:
session:
cookieSamesite: Lax
Pojďme k dál.
Změny na webu by správně měly dělat jen POST požadavky, ale zcela
běžně se k tomu používají i GET požadavky, tedy odkazy, jako
například <a n:href="...">smazat</a>
. U těchto
odkazů také nechceme, aby je bylo možné vyvolat útočníkem z jiné
domény. Řešením je buď odkazy zaměnit za tlačítka, u kterých ochranu
zajišťuje už výše uvedená ochrana cookie se session ID, nebo zůstat
u odkazů a kontrolovat na straně presenteru, zda akce byly vyvolány ze
stejné domény.
Ukázka nahrazení odkazu za POSTové tlačítko:
odkaz
<a n:href="...">smazat</a>
nahradíme za tlačítko (pozn. attribut form nefunguje v IE 11)
<button formaction="..." form=postform>smazat</button>
+ na začátek stránky přidáme
<form id=postform method=post></form>
Pokud nepoužijeme tlačítko a zůstaneme u odkazů, je třeba kontrolovat na straně presenteru, zda akci vyvolal náš server.
Nejprve tedy aktivujeme podporu pro tuto feature pomocí konfigurace:
http:
sameSiteProtection: yes
# zároveň aktivuje i výše uvedené cookieSamesite: Lax, které už není potřeba nastavovat
A pro test na straně presenteru poslouží metoda
Nette\Http\Request::isSameSite()
. Pokud odkaz nebyl odkliknut na
našem serveru, musíme uživatele přesměrovat jinam, protože opakovaný
požadavek vyvolaný stisknutím tlačítka refresh by už nemohl být tímto
způsobem chráněn.
class MyPresenter extends Presenter
{
public function handleDelete(int $id)
{
if (!$this->getHttpRequest()->isSameSite()) {
$this->redirect('Sign:out');
}
}
}
Pokud na web přijdeme s prohlížečem, který SameSite cookie nepodporuje, vše bude fungovat, jen prostě odkazy nebudou chráněné. Proto není třeba váhat s nasazením této doplňující ochrany.
Doplněno:
Jak vypadá podpora v Nette 3?
V Nette 3 je ochrana signálů automaticky aktivní a nebude nutné ji aktivovat v konfiguraci. Netýká se to však session cookie, která příznak samesite kvůli odlišnostem v implementaci prohlížečů nemá.
Kontrolu jde pro konkrétní signál vypnout uvedením anotace:
class MyPresenter extends Presenter
{
/**
* @crossOrigin
*/
public function handleDelete(int $id)
{
}
}
- David Grudl
- Nette Core | 8227
Bezpečnostní věci jsou vždycky složité na pochopení, s tím se nedá moc dělat.
- Lukes
- Silver Partner | 68
David Grudl napsal(a):
Pokud nepoužijeme tlačítko a zůstaneme u odkazů, musíme kontrolovat na straně presenteru, zda je vyvolal náš server. To by se v Nette 3 zřejmě zjednodušilo na uvedení anotace:class MyPresenter extends Presenter { /** * @secured (nebo @samesite ?) */ public function handleDelete(int $id) { } }
Nebylo by lepší se k tomu chovat jako k escapování, což znamená, že pokud nic neuvedu, tak je to ve výchozím nastavení nastavené a anotací to deaktivovat? Je tu nějaký důvod(bezpečnostní, výkonový…) proč by to tak nemělo být? Je to sice BC break, ale to by u Nette 3 nemuselo vadit. Přece jen víš jestli je použitý GET nebo POST.
Editoval Lukes (4. 9. 2018 10:32)
- David Grudl
- Nette Core | 8227
Myslíš v případě signálů, tedy metod handleXyz()
? To
není špatný nápad, asi to zkusím nasadit a uvidíme, jak se to
osvědčí.
- David Grudl
- Nette Core | 8227
Ještě je otázka, jak se v případě neoprávněného přístupu zachovat. Asi bude nutné někam přesměrovat, zobrazit jen chybovou stránku nestačí, protože uživatel by mohl stisknout F5 a tím požadavek zopakovat, ale tentokrát už by byl vyvolaný ze same site.
- ali
- Člen | 342
David Grudl napsal(a):
Ještě je otázka, jak se v případě neoprávněného přístupu zachovat. Asi bude nutné někam přesměrovat, zobrazit jen chybovou stránku nestačí, protože uživatel by mohl stisknout F5 a tím požadavek zopakovat, ale tentokrát už by byl vyvolaný ze same site.
Co takhle nastavit destinaci v configu?
Pripade pokud by si nekdo nejaky konkretni handle chtel prizpusobit, tak by se to mohlo nastavit pres anotaci.
Editoval ali (4. 9. 2018 16:50)
- Lumeriol
- Generous Backer | 63
Napadá někoho, jak vyřešit problém typu:
Eshop – objednávka – přesměrování na platební bránu na jiný web (přes presenter->redirect) – návrat z platební brány na původní stránku bez zrušení sessions?
Respektive je možné vypnout tuto kontrolu pouze pro část webu, či spíše mít z některých domén povolený přístup?
- ic
- Člen | 430
Asi dobré to nasadit co možná nejdříve… podle posledního oznámení
Googlu ( https://thehackernews.com/…cookies.html ) totiž bude
v Chromu i funkce pro odstranění sledovacích cookies. A to která cookie
je a není „sledovací“ se bude rozhodovat právě podle nastavení
SameSite
. A cookies postaru bez jakéhokoliv nastavení se budou
interpretovat jako cookie třetí strany a pokud bude uživatel paranoidní a
často je mazat bude se z takového webu i často odhlašovat. Mít to
nastavené už dopředu (Google to zatím jen ohlásil jako plán, nic
konkrétního zatím v Chromu není) může zajistit, že se nepromažou
i dlouhodobější cookies, které nastavuji už teď i když by ta funkce
měla přijít až za X měsíců.
- David Grudl
- Nette Core | 8227
Chrome říká, že future release of Chrome will only deliver cookies
with cross-site requests if they are set with SameSite=None
and
Secure
.
Pokud máš cookie, u které chceš, aby byla přenášena cross-site, tak při vytvoření nastav SameSite na None.
Secure jde zapnout globálně https://doc.nette.org/cs/configuring#…