Webspire

Administrační systém

CSRF ochrana formulářů v Nette a NW7

Nette podporuje CSRF ochranu formulářů, prostřednictvím skrytého formulářového pole, do kterého se uloží CSRF token, jenž se s vygenerováním zapamatuje v session a po odeslání se token, uložený v session, ověřuje vůči odeslanému tokenu.

Pokud jste někdo něco podobného nasadili, pravděpodobně jste se již setkali s problémem, kdy vykreslení formuláře způsobí varování “HTTP headers already sent”. Zkrátka, že se pokoušíte (v tomto případě) startovat session až v okamžiku, kdy již HTTP hlavičky byly odeslány a není možné již poslat další. To se typicky děje, pokud máte nakonfigurovanou Nette session v režimu autoStart: smart - tedy “vytvoř session až v okamžiku, kdy je potřeba”. Za předpokladu, že využíváte výchozí souborové úložiště pro session ID na straně server, je toto chování výhodné v tom, že se nevytváří nové session soubory s každým přístupem nového uživatele, avšak vytvoří se, až když je potřeba skutečně do session něco zapsat. To však může být právě v kombinaci s CSRF ochranou formulářů problém. Nastartování session totiž způsobuje zapsání session ID do cookie (pokud ještě nebylo vygenerováno), které se přenáší právě skrz HTTP hlavičky. Jenže ty již mohly být v onen okamžik odeslány a problém je na světě.

Nejjednodušším řešením je přepnout Nette session do režimu autoStart: true, tedy aby se starovala automaticky. Díky tomu bude session ID cookie již nastavena a nestane se vám, že by se ji Nette pokoušelo vytvářet až na žádost, např. v okamžiku vykreslování stránky, kdy už jsou HTTP hlavičky poslány.

Druhou možností je před samotným vykreslením (typicky ještě před zpracováním signálu někde ve startup/action* metodě) inicializovat formulář tak, aby se vždy před vytvořením kompletně sestavil, a tím pádem se natartovala session před započetím vykreslování HTML stránky.

Automatické startování session má však i své nevýhody:

  1. Může způsobit velké množství session souborů na serveru (např. přístupy robotů a crawlerů). Tento problém lze řešit detekcí, zdali je uživatel robot či opravdový člověk a popřípadě, zdali si můžete dovolit  takovému klientovi změnit úložiště session na serveru tak, aby se žádný soubor nevytvářel - např. použitím Kdyby\FakeSession. Podobným způsobem to řešíme i v Netwings 7, ale o tom až někdy příště.
  2. Dokud je session otevřená (od otevření přes session_start() až po uzavření přes session_write_close()), je blokován konkurenční přístup v rámci jednoho session ID, jelikož jednotlivé požadavky by si mohly  ovlivňovat session pod rukama.

V Netwings 7 máme tuto ochranu zapnutou by-default na produkčním prostřední nad všemi formuláři. Pokud vývojář chce, může ji vypnout (nad konkrétním formulářem nebo i globálně). Navíc máme upravený způsob vykreslení formulářového prvku CsrfProtection takovým způsobem, že se samotný HTML input s tokenem vykresluje pouze jako data-atribut jiného (div) elementu a poté až Javascript způsobí jeho vložení do formuláře.

Tím vynucujeme mít povolený a aktivní Javascript. V dnešní době se bez Javascriptu na webu beztak neobejdete, čili pro běžného uživatele to není nijak limitující a alespoň tím určitým způsobem odstřihnete případné “hloupé” roboty (ve smyslu neumějící Javascript) nabízející viagry a podobné srandy za úžasné ceny.

Sdílet:
###message