Přeskočit na hlavní obsah

Session ID do URL nepatří

V článku Session hijacking aneb ukradení session ID jsem předeslal, že předávání SID přímo pomocí parametrů v URL je špatné. Lze na ně totiž použít drtivou většinu všech útoků pro ukradení či podvržení SID, zatímco předávání pomocí cookies je proti mnohým z nich relativně odolné. Pojďme se na to podívat blíže.

Jak to funguje?

PHP má pro vkládání session ID do URL parametrů zabudovanou podporu. Pro vývojáře je to poměrně pohodlné, nemusí se o nic starat, nanejvýš zapne jednu dvě direktivy a všechno ostatní se udělá samo.

Všechny výstupní URL se pak začnou automaticky přepisovat na něco jako www.example.com?PHPSESSID=72825ba3a53507f1abd51e0e877b5b1a, stejný token se začne v podobě skrytých polí vkládat i do všech formulářů.

Server se pak při každém příchozím požadavku sám dívá do příslušného parametru a pokud je nastaven, spáruje jej s odpovídajícími uloženými session daty.

Co je na tom špatně?

Předávání SID přes URL a potažmo i přes skrytá formulářová pole ale přináší oproti cookies několik dodatečných slabých míst. Která to jsou?

Logy po cestě
Během nešifrované komunikace se URL po cestě loguje na řadě různých routerů, proxy serverů apod. Z každého z nich lze předávané SID snadno získat. Cookies se naproti tomu zpravidla nelogují.
Historie prohlížeče
URL se ukládají do historie prohlížeče. Pokud k počítači přijde někdo další, může si z historie příslušná URL otevřít a směle v načaté session pokračovat. Naproti tomu relační cookies se při uzavření prohlížeče mažou.
Záložky
Totéž platí i pro záložky. O řád vyšší riziko pak přichází, pokud uživatel používá pro bookmarky nějakou webovou službu, kde své odkazy navíc sdílí s ostatními.
Zveřejnění URL
Kromě záložkovacích služeb posílají uživatelé svá URL do světa i řadou dalších cest, typicky kamarádům přes ICQ nebo e-mail.
Referery
Při prokliku někam jinam předává prohlížeč cílovému serveru v hlavičce Referer naše URL, a to včetně aktuální otevřené session.

Pozor na referery

Posledně jmenované referery si zaslouží pár slov navíc. Pravděpodobnost, že autor webu odkáže schválně zrovna na útočníkovu stránku, není příliš velká. Útočník ale často může vložit do webu vhodný odkaz sám. Buď s využitím nějaké díry (například XSS), anebo zcela legálně, třeba do příspěvku v diskuzi.

U obojího samozřejmě platí, že aby se URL předala, musí se oběť skrz odkaz prokliknout. Existují i způsoby útoků využívající předávání refereru, které se obejdou bez prokliku uživatele.

Jedná se vlastně jakoby o „obrácený XSRF“. Útočník tehdy vloží do napadeného webu kód, který pak při každém zobrazení natahuje nějaký externí prvek z útočníkova serveru. Může se jednat například o obrázek nebo o iframe. Každý takový dotaz pak předává útočníkovu serveru v hlavičce Referal právě URL napadené stránky i s připojeným SID.

Krádež skrze XSS

Další možností, jak ukrást session ID z URL stránky, je využití případné Cross-site scripting zranitelnosti. Útočník prostřednictvím XSS díry vloží do napadeného webu JavaScriptový kód. Ten se pak při otevření stránky spustí, vypreparuje si SID přes DOM (například z odkazů nebo z objektu document.location) a pošle ho útočníkovi na pozadí.

Cross-site scripting poskytuje vůbec v oblasti kradení SID nepřeberné množství zábavy. Útočník pomocí něj může třeba měnit cíl odesílaných formulářů, ty se pak odešlou na jeho vlastní server, a to včetně session ID přiloženého do skrytého pole. Na některé další možnosti narazíme v dalších dílech tohoto seriálu. Každopádně je dobrý nápad mít na webu XSS pořešené.

Další nevýhody

Session ID přidávané do parametrů vytvářejí duplicitní URL. Jedná se o situaci, kdy na jednu a tutéž stránku vede více různých URL. Duplicity způsobují velké problémy například při indexaci webu roboty vyhledávačů a patří mezi klasické SEO chyby. Mají ale i některé negativní dopady do použitelnosti webu.

PHP dále nepřidává session ID úplně všude. Programátor na to musí myslet a přihodit SID na konec některých URL ručně. Typickým případem, kdy se na to zapomíná, jsou 30x přesměrování pomocí HTTP hlavičky Location.

Prostě to všechno zakázat

Jasným řešením všech uvedených rizik a problémů je zakázat předávání session ID pomocí URL a předávat je jen pomocí cookies.

Zajisté, tím okamžikem přestanou sessions fungovat uživatelům se zakázanými relačními cookies. Nicméně:

  • Pokud někdo tak moc myslí na svou bezpečnost, že si zakazuje ukládání cookies, má obecně smysl zakázat jen trvalé cookies se zadanou dobou platnosti. Relační cookies jsou poměrně neškodné. Stejně tak pokud některé firewally filtrují cookies, tak to dělají opět pro cookies se zadanou dobou platnosti, zatímco session cookies propouštějí zpravidla bez problémů
  • Pokud je někdo tak paranoidní, že si zakazuje i relační cookies, v důsledku čehož mu už dnes nebude fungovat polovina věcí na webu, dobře mu tak. To už není chyba vaší webové aplikace, ale případ pro doktora Chocholouška.

Jak to tedy zakázat?

Přidávání SID do všech výstupních URL se ovlivňuje konfigurační direktivou session.use_trans_sid. Stačí tedy v souboru php.ini nastavit:

session.use_trans_sid = 0

Alternativně lze tuto změnu provést i v souboru .htaccess:

php_flag session.use_trans_sid off

či přímo ve své aplikaci, kde to ale musíte provést ještě před prvním zavoláním funkce session_start():

ini_set('session.use_trans_sid', FALSE);

Tohle ale občas nemusí fungovat, proto je dobré zákaz pojistit ještě nastavením prázdného řetězce do direktivy url_rewriter.tags:

ini_set('session.use_trans_sid', FALSE);
ini_set('url_rewriter.tags', '');

A dále?

V uvedeném kontextu se často uvádí i další dvě direktivy, a to session.use_cookies a session.use_only_cookies, ideálně obě zapnuté:

session.use_cookies = 1
session.use_only_cookies = 1

Ty ale ve skutečnosti automatické vkládání SID do URL nijak neovlivňují. K jejich skutečnému významu se dostanu v příštích pokračováních tohoto seriálu.

Seriál o bezpečnosti sessions

  1. Nenechte si uhodnout Session ID
  2. Session hijacking aneb ukradení SID
  3. Sidejacking aneb nasloucháme v síti
  4. Session ID do URL nepatří (právě čtete)
  5. Předávání SID pomocí cookies
  6. Bráníme se zneužití ukradeného SID
  7. Session fixation aneb nenechte si podstrčit SID

Komentáře

  1. Už se těším na září 2010 na další díl :-).

  2. Proč září, když stačí prosinec? :)
    No ale jinak doufám, že se dočkáme dalšího dílu dříve než v prosinci (září)…

  3. Pěkný článek, už se těším na další. Snad příjde brzo:)

  4. No jo, no jo, no jo. Jak říká děda Potůček: „Je to už úplně hotový, akorát zbývá to dodělat.“

  5. Souhlasím s tím, co jste napsal, ale praxe je někdy neuvěřitelná.

    Pro jednoho zákazníka jsem dělal obchod. Vše bylo ok a mělo dojít k zaplacení. Druhý den večer jsem měl ovšem v telefonu huláka, že jeden zákazník nemohl v obchodě objednat. Když jsem zjistil, že má vypnuté cookies tak jsem doporučil jejich zapnutí. Jenže ten zákazník se kousnul s tím, že je to nebepečné a dokonce to hlásili na Nově a majitel obchodu mi jasně řekl, že si nemůže dovolit přijít o zákazníka…

    No nevysvětlil jsem mu to a SID do URL dal, jinak bych proplacenou fakturu neviděl…

  6. Slabá místa jsou posaná velmi pěkně. Nemyslím si ale, že je moudré naprosto odsoudit SID v URL. Za prvé – dovedu si představit případy kdy naopak hrozí zneužití cookie, ale zásadní je přesně to, co píše pan Raška ve svém commentu. Zákazníkovi je naprosto ukradené jak je session funkcionalita implementována a sám jsem byl překvapen kolik lidí má cookies zakázané. A aplikace se zpravidla dělá pro zákazníka, že? Osobně to řeším tak, že pokud jsou vypnuté cookies, posílám SID v URL – mám s tímto kompromisem dobré zkušenosti.

  7. Vďaka za články. A čo pokračovanie? Prešlo už pár rokov, tak máte určite nové skúsenosti…