Sdílení session mezi protokoly HTTP a HTTPS

Je možné zajistit bezpečné sdílení HTTP session mezi oběma protokoly? Z dostupné dokumentace se dozvídáme, že nikoliv. Tento článek se zabývá možným řešením, které za jistých podmínek umožňuje bezpečně sdílet společnou session. Důvod proč se tímto problémem zabývat je jednoduchý - SSL šifrování je výpočetně nákladná věc (viz. např. Performance analysis of Secure HTTP Protocol). Proto je možná vhodné používat HTTPS pouze tam, kde je k tomu důvod (tedy např. uživatel pracuje s některými důvěrnými daty). Jistě se shodneme na tom, že na řadě webových aplikací je takto důvěrných míst pouze pár a zbytek bychom mohli hnát klidně přes protokol HTTP, čímž odlehčíme svému webovému serveru. Jenže tady narážíme na zásadní problém - nemůžeme nechráněným protokolem vyzradit identifikátor session (a naopak nesmíme akceptovat session, která vznikla přes protokol HTTP). Má tedy tato situace řešení, nebo nemá, jak se dočteme v řadě publikací?

Kolega Martin Veska ze společnosti FG Forrest přišel s návrhem řešení, které by umožňovalo bezpečně “vyzradit” identifikátor session, aniž bychom se vystavili riziku záměny autorizovaného uživatele. Jako každé jiné řešení má i toto své mínus, ale o tom až později v článku.

###

Sdílení session mezi oběma protokoly je problémová věc. Lépe řečeno - bezpečnostní díra. Typicky totiž po autentizaci uživatele nahrajete informace o něm (často i jeho oprávnění do session) a při dalším dotazu už pracujete s těmito informacemi (po prvotní autentizaci už uživateli “věříte”). Dotazy jsou mezi sebou provázány identifikátorem, který je posílaný prohlížečem uživatele (JSESSIONID), a který zajistí, že při dalším požadavku vám web server poskytne “tu jeho” serverovou session. Identifikátor je buď posílán jako cookie (obvykle) nebo v případě, že uživatel má zakázané cookies v URL.

Slabé místo je právě ve fázi předávání identifikátoru od uživatele na server a zpět. V případě, že tento identifikátor putuje nešifrovaným kanálem (HTTP), existuje teoretická šance, že jej může někdo odposlechnout a vydávat se za uživatele, jehož komunikaci odposlechl (prostě vám pošle stejný identifikátor ze svého počítače a vy na straně serveru nemáte šanci jak rozeznat, že se jedná o podvrh - opomineme-li problémové ověřování IP klienta). Proto se všude uvádí, že jediná bezpečná komunikace mezi serverem a uživatelem je 100% se držet šifrovaného spojení (tedy HTTPS).

Dokladem je např. úryvek z dokumentace Acegi Security:

“An important issue in considering transport security is that of session hijacking. Your web container manages a HttpSession by reference to a jsessionid that is sent to user agents either via a cookie or URL rewriting. If the jsessionid is ever sent over HTTP, there is a possibility that session identifier can be intercepted and used to impersonate the user after they complete the authentication process. This is because most web containers maintain the same session identifier for a given user, even after they switch from HTTP to HTTPS pages. If session hijacking is considered too significant a risk for your particular application, the only option is to use HTTPS for every request. This means the jsessionid is never sent across an insecure channel. You will need to ensure your web.xml -defined points to a HTTPS location, and the application never directs the user to a HTTP location. Acegi Security provides a solution to assist with the latter.”

Ke ztrátě důvěryhodnosti navíc může dojít i na první pohled ne zcela viditelným způsobem. V případě, že vaše aplikace poskytuje alespoň jediný servlet dostupný protokolem HTTP, který během své činnosti nastartuje serverovou session (request.getSession(true)) - webový server tuto session vytvoří, přidělí ji identifikátor a ten odešle v odpovědi klientovi nešifrovaným kanálem jako cookie JSESSIONID. Přestože by uživatel hned dalším dotazem mířil na vaši aplikaci již přes protokol HTTPS, odešle spolu s requestem také již vytvořené JSESSIONID (jelikož se jedná o “nesecure” cookie prohlížeč ji může poslat jak kanálem HTTP, tak i HTTPS). Webový server ale tento identifikátor již akceptuje a při požadavku na session, již žádnou novou nevytváří, ale poskytne už tu vytvořenou - tzn. v takovémto případě uživatel sdílí session jak pro přístup přes HTTP tak i přes HTTPS - ale rozhodně není v bezpečí.

Jiný problém nastává v opačném případě, kdy uživatel jako první přistoupí na váš servlet přes HTTPS kanál. V takovém případě opět webový server při požadavku na session tuto session vytvoří, přidělí identifikátor, ale identifikátor posléze pošle klientovi ve formě tzv. “secure cookie”. To znamená, že webový prohlížeč tuto cookie nesmí za žádných okolností poslat zpět serveru nešifrovaným (HTTP) kanálem. Mnohé potom překvapí, že když uživatel v dalším požadavku přistoupí opět na naši aplikaci tentokrát přes HTTP, webový server nám vytvoří úplně novou session - a tudíž nevidíme uživatelova data, které jsme si uložili v předchozím volání. To je způsobeno tím, že prohlížeč správně neodeslal identifikátor session, uložený v secure cookie nešifrovaným kanálem. Tentokrát jsme v bezpečí - ale aplikace nám nefunguje, tak jak bychom si představovali.

Řešení problému

K vyřešení tohoto problému postačují dvě jednoduché věci. Ty musíme ovšem provádět na straně serveru před zpracováním jakéhokoliv requestu (v našem případě jsme to vyřešili nasazením servletového filtru). Jeho kód uvádím níže:

Konfigurace ve springu potom takto (puze výňatek z komplexnější Acegi konfigurace):

Zajištění spolehlivého sdílení session

První věcí je vyřešení neblahého stavu, kdy session vytvořená v HTTPS requestu není viditelná v následném HTTP požadavku. Toto je možné jednoduše vyřešit tím, že i v případě prvního přístupu přes HTTPS vynutíme odeslání JSESSIONID cookie jako ne secure.

Tím je sice problém vyřešen, ale otvíráme bránu k odposlechnutí této informace. Proto musíme bezpečnost zajistit nějak jinak.

Zajištění bezpečného přístupu přes HTTPS

Při prvním přístupu protokolem HTTPS, vytvoříme tzv. secure token - což je unikátní řetězec (vypočtený např. na základě JSESSIONID + nějakého dalšího modifikátoru) , který odešleme uživateli v odpovědi jako secure cookie. Tento token nám v podstatě nahrazuje původní důvěryhodnou JSESSIONID, kterou jsme byli nuceni vyzradit. Secure token nám prohlížeč odešle vždy, když uživatel bude přistupovat na naši aplikaci přes HTTPS a jen tehdy můžeme na straně serveru ověřit, že uživatel je skutečně stále ten stejný uživatel, kterého jsme přihlásili.

Z výše uvedeného tedy vyplývá následující základní pravidlo: jakékoli operace, u kterých si chceme být jisti, že je skutečně provádí uživatel, kterého jsme přihlásili (jako např. změna hesla, přihlášení, změna údajů uživatele, odeslání objednávky atp.), musíme provádět pouze přes protokol HTTPS - jelikož jen v něm je možné zkontrolovat secure token.

Při každém následujícím požadavku přes protokol HTTPS filtr zkontroluje zda spolu s JSESSIONID přišel také správný secure token, který byl pro tuto session na počátku vygenerován. Jakmile tento secure token nepřijde nebo se liší od vydaného tokenu pro konkrétní session, filtr nepovolí zpracování požadavku a vrátí HTTP Error 403 - Forbidden.

Z toho také vyplývá omezení, že uživatelé, kteří nemají povolené cookies nebudou moci s naší aplikací (konkrétně tedy s částí přístupnou pouze přes HTTPS) pracovat. Podobná logika není možná zajistit v případě URL rewritingu.

Závěrem

Výše uvedený článek má celkem dva cíle. Jednak se podělit s komunitou o naše myšlenky a druhak si ověřit, jestli přeci jen není možné najít způsob, kterým by bylo možné výše popsanou logiku obejít a přihlášení nějakým způsobem zneužít. Celou problematiku jsme analyzovali z různých stran a toto řešení nám připadá jako bezpečné. Jak se ovšem říká - “nikdy neříkej nikdy” a proto budeme vděčni za vaše názory, či myšlenky, jak by bylo možné popsané zabezpečení “prostřelit”.

Podělte se s ostatními:
  • Digg
  • del.icio.us
  • De.lirio.us
  • Technorati
Ohodnoťte článek:
Takovéhle články už radši ne!Nic nového pod sluncem.Průměr - obsahuje zajímavé střípky informací.Hodnotný článek - lecos nového jsem se dozvěděl.Skvělý článek - informace se mi dost hodí. (3 hlasů, průměrně: 3.33 z 5)
Loading ... Loading ...

Bez reakcí. to “Sdílení session mezi protokoly HTTP a HTTPS”

  1. tomas kouba:

    Mě to připadá bezpečné a chytré…

Nechte zde svůj komentář

Opište prosím text z obrázku: