Sessions a ošetření timeoutu

HTTP je sám o sobě bezstavový protokol, za normálních okolností tak server odpovídá na jednotlivé dotazy klienta, aniž by si je navzájem dával do souvislostí. Proto většina programovacích jazyků a vývojových prostředí zavádí na aplikační úrovni mechanizmus sessions. Pro každou session vygeneruje server při prvním dotazu jedinečný identifikátor – session token. Ten odešle klientovi, který si jej uloží jako cookie a odesílá serveru s každým dalším dotazem. Server si tak podle něj může navzájem pospojovat všechny klientovy dotazy.

Donedávna se pro předávání session tokenu hojně používalo také přepisování všech odkazů ve stránce, kdy se session token přidával jako další parametr k danému odkazu. Do formulářů se zase analogicky vkládalo příslušné skryté pole. Tím se zpřístupnilo využití sessions i pro prohlížeče, které cookies nepodporovaly, nebo je měly vypnuté. Tento přístup nicméně rapidně zvyšoval riziko ukradení session případným narušitelem. Kvůli upravené podobě všech otevíraných URL se totiž aktuální session token ukládal do historie prohlížeče i do všech možných logů během cesty po síti. Často se stávalo i to, že uživatel poslal zajímavé URL někomu e-mailem či je dokonce zveřejnil v některé diskuzní skupině, ale opět včetně identifikace své session. Z těchto důvodů (a díky masové podpoře cookies všemi běžně používanými prohlížeči) se vkládání session tokenu přímo do URL nedoporučuje a měla by se používat výhradně cesta přes cookies.

Session token by měl být podle [20] unikátní, nesnadno odhadnutelný, odolný proti dekompozici. Nebezpečí ukradení tokenu útokem hrubou silou, kdy útočník postupně zkouší jeden potenciální token za druhým, eliminuje jeho dostatečná délka, díky které se tento způsob útoku stane v daném časovém limitu výpočetně neuskutečnitelný. Session token je vhodné nějakým způsobem navázat na aktuálního klienta, aby se zabránilo jeho ukradení či replay–attacku, například omezením na konkrétní IP adresu, daný typ prohlížeče apod. Pro ukládání tokenu by se měly používat neperzistentní cookies (také často nazývané „session cookies“), které prohlížeč neukládá na disk a uchovává je jen v RAM paměti. Při zavření okna prohlížeče je tak session token ztracen a případný další uživatel počítače nemůže ve stejné session pokračovat.

Session je většinou vytvářena hned při prvním dotazu klienta, bez ohledu na to, zda je uživatel přihlášen či nikoliv. Po úspěšné autentizaci uživatele, kdy je ověřeno zaslané uživatelské jméno a heslo, je toto přihlášení interně spojeno s existující aktuální session. Alternativně lze session vytvářet právě až po úspěšné autentizaci.

Prohlížeč pak s každým dalším dotazem zasílá opět jen session token. Aplikace však už ví, který uživatel je s ním asociován – dochází k entitní autentizaci na základě zaslaného session tokenu. Tak je tomu až do doby, kdy se uživatel odhlásí z aplikace. Pak je vazba mezi aktuální session a přihlášením zrušena. Alternativně opět může být bezprostředně po odhlášení zrušena i celá session.

Hlavním důvodem evidence sessions je možnost navázat na ně některé proměnné a přenášet si jejich hodnoty napříč jednotlivými požadavky uživatele. V minulosti se pro tento účel používaly přímo cookies. To však není příliš šťastné řešení, neboť kterýkoliv uživatel může libovolným způsobem ovlivnit obsah zasílaných cookies. Například pokud bychom chtěli mezi různými požadavky přihlášeného uživatele přenášet jeho identifikační číslo nebo rozsah přiřazených oprávnění, může si je případný útočník změnit na jinou hodnotu, zaslat takto modifikovaný požadavek a získat tím jednoduše práva úplně jiného uživatele [12]. Naproti tomu uchovávání hodnot v session proměnných je v tomto ohledu bezpečné, neboť je pod plnou kontrolou aplikace.

V jazyce PHP je podpora sessions standardně zabudována od verze 4. Pro tento účel je definována sada funkcí Session_*, které umožňují vytvoření či zrušení session, nastavení session tokenu, registrování či odregistrování session proměnných apod. Interpret většinu správy session obstarává sám, takže v nejednodušším případě stačí jen registrovat session proměnnou a systém automaticky vytvoří session, vygeneruje session token, uloží jej do paměti prohlížeče, kontroluje platnost již existujících sessions apod. Je podporováno jak uložení session tokenu do cookies, tak i transparentní vkládání session tokenu do všech odkazů a formulářů na stránce.

Ve starších verzích PHP zajišťovala podporu sessions kdysi rozšířená a populární knihovna PHP Base Library.

Timeout a ošetření nezpracovaných dat

Mechanizmus sessions a na ně navazovaných přihlášených uživatelů, tak jak byl zatím popsán, má jednu zásadní vadu. Jestliže se totiž uživatel po skončení své práce zapomene explicitně odhlásit, zůstává na serveru otevřená session, navíc ještě s přiřazeným přihlášením uživatele. Případný útočník má tak neomezeně dlouhou dobu, po kterou má čas hrubou silou vyzkoušet postupně všechny možné podoby příslušného session tokenu.

Z tohoto důvodu se zavádí timeout nepoužívaných sessions resp. timeout přihlášení. Aplikace sleduje u každého přihlášeného uživatele čas uplynulý od jeho posledního dotazu na server. Překročí-li určitou hodnotu, je uživatel automaticky odhlášen resp. je jeho session zrušena. Dostatečně krátký timeout v kombinaci s dostatečně dlouhým session tokenem zajistí, že dojde ke zrušení příslušné session dříve, než útočník stihne zaslat i jen zlomek možných tokenů.

V některých případech ale může být timeout přihlášení nepříjemný. Jedná se zejména o situace, kdy uživatel mezi dvěma požadavky provádí nějakou déletrvající činnost. Typicky píše ve webmailové aplikaci text elektronického dopisu. Než jej stačí dopsat, uplyne timeout a systém provede automatické odhlášení. Po odeslání dopisu pak server odeslaná formulářová data nezpracuje a pošle uživateli zpět třeba jen login formulář. Za normálních okolností je celý pracně vytvořený e-mail nenávratně ztracen.

Takové nežádoucí chování aplikace by proto měl framework ošetřit. V principu jde o to nějakým způsobem dočasně uchovat všechna zaslaná formulářová data a zpracovat je bezprostředně po úspěšném přihlášení do aplikace.