Nette Framework: Sessions

Pokud chcete naprogramovat šikovnější webovou aplikaci, neobejdete se bez sessions. Ukážeme si, jak Nette Framework zjednoduší práci se sessions a jak řeší s tím spojená bezpečnostní rizika.

Seriál: Začínáme s Nette Framework (17 dílů)

  1. Nette Framework: zvyšte svoji produktivitu 10.3.2009
  2. Nette Framework: Odvšivujeme 17.3.2009
  3. Nette Framework: MVC & MVP 24.3.2009
  4. Nette Framework: Refactoring 31.3.2009
  5. Nette Framework: Chytré šablony 7.4.2009
  6. Nette Framework: adresářová struktura aplikace 14.4.2009
  7. Nette Framework: AJAX 21.4.2009
  8. Nette Framework: AJAX (pokračování) 28.4.2009
  9. Nette Framework: AJAX (dokončení) 5.5.2009
  10. Nette Framework: Sessions 12.5.2009
  11. Nette Framework: Přihlašování uživatelů 19.5.2009
  12. Nette Framework: Ověřování oprávnění a role 26.5.2009
  13. Nette Framework: Neprůstřelné formuláře 2.6.2009
  14. Nette Framework: Neprůstřelné formuláře II 9.6.2009
  15. Nette Framework: Neprůstřelné formuláře III 16.6.2009
  16. Nette Framework: Cache 23.6.2009
  17. Nette Framework: Co se do seriálu nevešlo? 30.6.2009

Protokol HTTP je bezestavový. Což znamená, že každý dotaz na server je nezávislý a že si server nepamatuje stav komunikace. Takto by však nebylo možné implementovat žádnou jen trošku složitější aplikaci, např. internetový obchod, který si potřebuje uchovávat obsah nákupního košíku. Proto byl protokol HTTP rozšířen o tzv. HTTP cookies, krátké textové řetězce, které umožňují informace o stavu uchovávat.

Chcete se naučit o Nette víc?

Akademie Root.cz školení Vývoj webových aplikací v Nette Framework. Kurz je určen všem programátorům v PHP, kteří se chtějí naučit tvořit webové aplikace rychle a kvalitně, bez bezpečnostních děr. Jako aplikační rámec slouží Nette Framework. Školí sám autor Nette – David Grudl. Máte zájem o jiné školení? Napište nám!

Jelikož tyto řetězce jsou skutečně krátké a ukládají se na straně prohlížeče, nemusí být vždy možné nebo vhodné do nich celý stav zapisovat. Řešením jsou tzv. sessions (česky relace, sezení). Princip je ten, že informace o stavu se uchovávají na straně serveru, kde jsou dostupné pod jedinečným identifikátorem zvaným Session ID a ten jediný stačí uložit do HTTP cookie.

Bezpečnost především

Server tedy předpokládá, že komunikuje stále s tímtéž uživatelem, dokud požadavky doprovází stejné Session ID. Úkolem bezpečnostních mechanismů je zajistit, aby tomu tak doopravdy bylo.

Když se někdy v devadesátých letech začalo diskutovat o bezpečnosti webových aplikací, vznikl mýtus, že cookies jsou samy o sobě nebezpečné a rádobyodborníci nabádali veřejnost, aby si je vypínala. Což samozřejmě ochromilo celou řadu webových aplikací. Aby mohly fungovat i bez cookies, začalo se Session ID přenášet také v URL. Což teprve zavdalo vzniku těch největších bezpečnostních děr. Obrácená kauzalita.

Dnes už je situace zcela jiná. Uživatelé si cookies nevypínají a bezpečnost aplikací má vysokou prioritu. Velmi důležité je tedy nakonfigurovat server tak, aby Session ID přenášel pouze v cookie, znepřístupnil jej JavaScriptu a případné identifikátory v URL ignoroval.

Nette Framework na scénu!

Jak už zaznělo v předcházejících dílech seriálu, Nette Framework klade velký důraz na bezpečnost aplikací. Připomeňme třeba šablonovací systém, který má ambici zcela eliminovat Cross Site Scripting. Nepřekvapí proto, že framework se snaží co nejlépe zabezpečit i sessions. Dělá to zcela transparentně, aniž byste museli cokoliv manuálně nastavovat.

Nette Framework tedy sám správně nakonfiguruje PHP direktivy*), kontroluje neměnost vybraných HTTP hlaviček zasílaných prohlížečem, v kritických okamžicích, jako je třeba přihlášení uživatele, vygeneruje Sesssion ID nové atd.

*) pro konfiguraci PHP se používá funkce ini_set, kterou bohužel některé hostingy nepovolují. Pokud je to případ i vašeho hostéra, pokuste se s ním domluvit, aby vám funkci povolil nebo alespoň server nakonfiguroval. Nevyhoví-li, vůbec neváhejte a hostéra změňte. Ušetříte si tak spoustu problémů.

Přístup k sessions obstarává objekt třídy NetteWebSession. Jelikož jde o singleton, nevytváříme jeho instanci přímo, ale vrátí ji metoda Environment::getSession(). Poté můžeme dokončit konfiguraci. Například takto lze nastavit dobu expirace, zvolit adresář pro soubory se stavem relací a upřesnit parametry cookie:

require 'Nette/loader.php';

$session = Environment::getSession();

// nastavení expirace: relace vyprší po 3 hodinách neaktivity
$session->setExpiration(3 * 60 * 60);

// nastavení cesty, kam se mají ukládat soubory na serveru
$session->setSavePath(dirname(__FILE__) . '/sessions/');

// nastavení parametrů cookie: bude dostupné jen na doméně forum.example.com
$session->setCookieParams('/', 'forum.example.com'); 

Konfigurace musí být provedena dříve, než se začnou session data používat. V aplikacích je nejvhodnější ji umístit do  bootstrap.php.

Ještě se zastavím u volby doby expirace. Výchozí hodnota „do zavření okna prohlížeče“ nemusí být vždy optimální. Metoda setExpiration() jako parametr akceptuje relativní čas v sekundách nebo UNIX timestamp, v aktuální verzi frameworku je možné použít i velmi srozumitelný textový zápis:

// relace vyprší po 14 dnech neaktivity
$session->setExpiration('+ 14 days'); 

Session není potřeba startovat nebo uzavírat, tohle provádí framework automaticky.

Jmenné prostory

V čistém PHP je datové úložiště session realizováno jako pole dostupné přes globální proměnnou $_SESSION. Problém je v tom, že aplikace se běžně skládá z celé řady vzájemně nezávislých částí a pokud všechny mají k dispozici jen jedno pole, dříve nebo později dojde ke kolizi názvů.

Nette Framework problém řeší tak, že celý prostor rozděluje na jmenné prostory. Každá část programu pak používá svůj jmenný prostor (s unikátním názvem) a k žádné kolizi již dojít nemůže. Se jmenným prostorem se pracuje podobně, jako by šlo o objekt:

// získáme přístup do jmenného prostoru 'myCounter'
$namespace = $session->getNamespace('myCounter');

// nastavíme proměnnou
$namespace->a = 'apple';
// lze použít i syntax: $namespace['a'] = 'apple';

// přečteme proměnnou
echo $namespace->a;

// zrušíme proměnnou
unset($namespace->a); 

Nette nabízí zkratku, místo Environment::getSession()->getNamespace('prostor') lze psát Environment::getSession('prostor').

Velmi užitečnou vlastností je možnost nastavit vlastní expiraci pro jednotlivé jmenné prostory nebo dokonce pro jednotlivé proměnné:

// jmenný prostor vyexpiruje po 60 sekundách
$namespace->setExpiration(60);

// a proměnná $namespace->a vyexpiruje už po 10 sekundách
$namespace->setExpiration(10, 'a'); 

Opět je možné kromě relativního času v sekundách použít UNIX timestamp nebo textový zápis. Zajímavostí je hodnota 0, který nastaví expiraci na okamžik, kdy uživatel zavře okno prohlížeče:

// proměnná $namespace->password vyexpiruje, jakmile uživatel zavře okno prohlížeče
$namespace->setExpiration(0, 'password'); 

Nezapomeňte, že doba expirace celé session musí být stejná nebo větší, než doba nastavená u jednotlivých prostorů či proměnných.

Pokračování příště

Příště se podíváme na přihlašování uživatelů.


Autor článku je vývojář na volné noze, specializuje se na návrh a programování moderních webových aplikací. Vyvíjí open-source knihovny Texy, dibi a Nette Framework a pravidelně pořádá školení pro tvůrce webových aplikací, které od podzimu 2009 nabídne kurz vývoje AJAXových aplikací.

David Grudl školí, je autorem PHP knihoven Nette Framework, databázové vrstvy dibi a formátovače HTML kódu Texy!.

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

Komentáře: 17

Přehled komentářů

Borek Bernard RE: Nette Framework: Sessions
smilelover RE: Nette Framework: Sessions
v6ak RE: Nette Framework: Sessions
Mastodont RE: Nette Framework: Sessions
v6ak RE: Nette Framework: Sessions
David Grudl RE: Nette Framework: Sessions
Mastodont RE: Nette Framework: Sessions
David Grudl RE: Nette Framework: Sessions
smilelover RE: Nette Framework: Sessions
v6ak Co ten Singleton?
Mastodont Re: Co ten Singleton?
David Grudl Re: Co ten Singleton?
v6ak Re: Co ten Singleton?
N pekne, ale pro me nepouzitelne
David Grudl Re: pekne, ale pro me nepouzitelne
juzna Concurrency
kubi Session in url
Zdroj: https://www.zdrojak.cz/?p=3006