Útok fixací na relaci (session fixation attack) je v informatice typ útoku, ve kterém se útočník snaží zneužít zranitelnost systému, která umožňuje jiné osobě zafixovat (vytvořit) na identifikátor relace (session ID, dále SID) jiné osoby. Většina těchto útoků se odehrává na webu a většina spoléhá na přijímání SID v rámci HTTP protokolu pomocí URL nebo POST dat.

Příklad útoku editovat

Použity jména z příkladu Alice a Bob.

Alice má účet u banky na adrese http://nebezpecny.priklad.cz/ . Alice bohužel není ohledně zabezpečení velmi svědomitá.

Mallory chce získat peníze z účtu Alice.

Mallory si získal důvěru (lhaní, phishing) Alice, která následuje odkazy poskytnuté Mallorym.

Jednoduchý postup útoku editovat

  1. Mallory zjistil, že http://nebezpecny.priklad.cz/ přijímá jakýkoliv identifikátor relace, přejímá textový řetězec z adresy (metodou GET) a nepoužívá žádné ověřování. http://nebezpecny.priklad.cz/ tedy není zabezpečená stránka.
  2. Mallory pošle Alici e-mail: "Ahoj, podívej se na tohle, v naší bance je skvělá nová funkce pro zobrazení transakcí, http://nebezpecny.priklad.cz/?SID=BUDU_VĚDĚT_TVOJE_SID/" . Mallory se snaží Alici vnutit adresu s předem definovaným SID ("BUDU_VĚDĚT_TVOJE_SID").
  3. Alice je zvědavá na funkci o které jí řekl Mallory a navštíví adresu http://nebezpecny.priklad.cz/?SID=BUDU_VĚDĚT_TVOJE_SID/ . Alice se klasicky přihlásí a její přihlášený účet bude vázán na SID "BUDU_VĚDĚT_TVOJE_SID".
  4. Mallory navštíví stejnou adresu poté, co Alice a tím získá přístup k jejímu účtu.

Útok za použití serverem generovaného SID editovat

Někteří lidé mají falešný dojem že servery, které akceptují pouze serverem generované identifikátory, jsou proti této metodě chráněné, není to však pravda.

Příklad:

  1. Mallory navštíví http://nebezpecny.priklad.cz/ a zjistí, zdali mu nějak byla přidělena SID. Server mu například nastaví cookie "SID" s hodnotou "0D6441FEA4496C2".
  2. Mallory pošle Alici e-mail: "Ahoj, podívej se na tohle, v naší bance je skvělá nová funkce pro zobrazení transakcí, http://nebezpecny.priklad.cz/ ?SID=0D6441FEA4496C2/".
  3. Alice klikne na odkaz a přihlásí se zafixovaným SID "0D6441FEA4496C2".
  4. Mallory navštíví odeslaný odkaz a má neomezený přístup k Alicině účtu.

Útok pomocí cross-site cooking editovat

Další útok tohoto typu lze provést pomocí cross-site cooking, využívající chyby prohlížeče, která dovolí stránce http://zlá.příklad.cz/ uložit cookie do Aličina prohlížeče pro jinou doménu http://dobrá.příklad.cz/, která je důvěryhodná. Tento útok může uspět dokonce i když nemá stránka http://dobrá.příklad.cz/ žádnou velkou bezpečnostní díru, jelikož stránka předpokládá, že spravování cookies v prohlížeči je zabezpečeno.

Příklad:

  1. Mallory pošle Alici e-mail s odkazem na jím vytvořenou stránku: "Čau, koukni na tuhle hustou stránku, http://coolbutevil.example.com/".
  2. Alice tuto stránku navštíví a bezpečností díra v prohlížeči umožní nastavit cookie "SID" s hodnotou "I_WILL_KNOW_THE_SID" pro doménu http://dobrá.příklad.cz/.
  3. Alice se časem přihlásí na stránku http://dobrá.příklad.cz/ a Mallory nyní může opět zneužít její účet na http://dobrá.příklad.cz/ jelikož i on má tuto cookie.

Z bezpečnostních důvodů by žádný moderní prohlížeč neměl dovolovat cross-domain cookies.

Útok pomocí cross-subdomain cooking editovat

Toto je stejné jako předchozí příklad, s tím rozdílem že se nespoléhá na bezpečnostní díru v prohlížeči ale na faktu že cookies mohou být na daném serveru nastaveny tak, aby byly platné na všech subdoménách.

Příklad:

  1. Webová stránky http://příklad.cz poskytuje subdomény (neověřené) veřejnosti.
  2. Mallory si založí subdoménu http://zlá.příklad.cz a naláká Alici na jeho stránku.
  3. Když Alice navštíví web, nastaví se jí pro doménu http://příklad.cz cookie s SID.
  4. Když Alice navštíví jakoukoliv subdoménu webu http://příklad.cz bude cookie k dispozici. Alice se tedy přihlásí na subdoménu která cookie přijme jakou svou vlastní.
  5. Mallory má přístup k tomuto sezení.

Každý z těchto příkladů vyústil v úspěšné získání práv udělených Alici, Mallorymu.

V alternativním příkladu by se Alice nemusela přihlásit na stránce. Mallory by mohl špehovat Alici a zneužít data která zadává. Mallory například použije předchozí útok a dát Alici jeho vlastní autentizované sezení, takže Alice by používala stránku s účtem Malloryho. Pokud se Alice rozhodne něco nakoupit a zadá údaje o platební kartě, Mallory by mohl být schopný získat tato (nebo jiná) data, prohlížením historie dat uloženým k účtu.

Protiopatření editovat

Nepřijímat identifikátory sekcí přes GET / POST editovat

Není doporučeno přijímat Identifikátory sekcí v URL (metoda GET) nebo proměnné v POST, jelikož mohou usnadnit tento útok - je velmi jednoduché vytvořit odkazy nebo formuláře které nastaví hodnotu proměnných přes GET / POST.

Identifikátory sezení (SID) také umožňují:

  • Únik SID při přechodu na jinou stránku pomocí HTTP referrer.
  • Únik k ostatním přes kopírování "zajímavých odkazů" z adresního řádku do chatu, diskuzního fora, ...
  • Vyhledání SID na mnoha místech (historie prohlížeče, záznamy webového serveru, záznamy poskytovatele připojení, ...)

Poznámka: Cookies jsou sdíleny mezi listy a okny prohlížeče. Mohou mezi sebou mít konflikt (adresy www.příklad.cz?code=site1 a www.příklad.cz?code=site2).

Může být tedy nutné poslat identifikátor v URL aby se obešla tato limitace. Pokud je to možné, použijte subdomény (www.site1.příklad.cz místo www.příklad.cz?code=site1), abyste se vyhnuli konfliktu cookies. To může ale vyústit v potřebu více certifikátů SSL.

Toto chování lze pozorovat na mnoha webech, pokud otevřeme více listů a snažíme se na nich zároveň vyhledávat. Některé z těchto sekcí poté mohou vracet nesmyslné výsledky.

Nejlepší řešení: ověření identity editovat

Tomuto útoku se lze většinou vyhnout pokud webový server změní uživatelovo SID když se přihlásí. Pokud je každý požadavek vázán na přihlášení ke stránce, útočník by musel znát SID přihlášeného uživatele. Když ale oběť navštíví odkaz poskytnutý útočníkem a přihlásí se, ID sezení se změní a původní odkaz nebude obsahovat platné SID oběti.

Podobné řešení lze taky použít jako ochranu před phishingovými a CSRF útoky.

Řešení: Uložení identifikátoru sezení v cookies editovat

SID je na většině moderních systémů uložen v cookies které mají rozumnou míru zabezpečí pokud systém ignoruje hodnoty GET/POST. Toto řešení je ale náchylné na CSFR útok a nesplňuje požadavky REST.

Řešení: Využít SSL / TLS identifikací sezení editovat

Pokud se povolí zabezpečení HTTPS, některé systémy dovolí obdržet SSL / TLS identifikátor sezení. použití SSL / TLS sezení je velmi bezpečné, ale mnoho jazyků pro vývoj webu neposkytuje plnou integrovanou funkcionalitu k tomuto zabezpečení. SSL / TLS sezení mohou být vhodné pouze pro kritické aplikace jako správa financí kvůli složitosti aplikace.

Vytvoření nového SID při každém požadavku editovat

Podobné řešení jako v prvním případě, ale nové SID se generuje při každém požadavku pro server. Pokud v tomto případě útočník uživatele přiměje k použití jemu známého SID, bude toto sezení neplatné pokud se ho útočník pokusí použít znovu. Implementace je jednoduchá:

  • Získat ID předešlého sezení OLD_SID pomocí HTTP požadavku
  • Pokud je OLD_SID null nebo prázdné, vytvoří se nové sezení
  • Vytvoření nového identifikátoru NEW_SID se zabezpečeným generátorem náhodných čísel
  • Sezení bude identifikováno pomocí SID=NEW_SID (a ne již pomocí SID=OLD_SID)
  • Přenést nové SID ke klientovi

Příklad:

Pokud Mallory naláká Alici k navštívení http://obět.příklad.cz/?SID=VÍM_SID, tento požadavek je poslán na obět.příklad.cz:

GET /?SID=VÍM_SID HTTP/1.1
Host: obět.příklad.cz

obět.příklad.cz přijme nastrčené SID=VÍM_SID. obět.příklad.cz je ale zabezpečená stránka, jelikož provádí znovuvytvoření sezení. Stránka zpět odešle:

HTTP/1.1 200 OK
Set-Cookie: SID=3134998145AB331F

Alice nyní bude používat SID=3134998145AB331F které Mallory nezná a SID=VÍM_SID není platné. Pokus o útok se tedy nezdařil.

Toto řešení bohužel nelze použít vždy, jsou známy problémy kdy problémy dělá software třetích stran jako například ActiveX nebo Java Applety. Když se pluginy pokouší komunikovat se serverem, může to způsobit odhlašování nebo rozdělení relace na dvě oddělené.

Pokud implementace obsahuje odesílání SID pomocí GET nebo POST, nemusí v některých prohlížečích fungovat tlačítko zpět, jelikož by se uživatel snažil dostat na stránku s již nevalidním SID.

Přijímání pouze serverem generovaných SID editovat

Další řešení je odmítnutí identifikátorů které nebyly generovány serverem. Toto ale nezabrání všem útokům tohoto typu.

if (!isset($_SESSION['SERVER_GENERATED_SID'])) {
   session_destroy(); // destroy all data in session
}
session_regenerate_id(); // generate a new session identifier
$_SESSION['SERVER_GENERATED_SID'] = true;

Funkce odhlášení editovat

Odhlašování je užitečné pro zabezpečení jelikož dovolí uživateli říct že toto sezení už nebude možno použít. Útok je tedy možný pouze dokud je sezení aktivní.

Zde je ukázka kódu, která však neposkytuje žádnou kontrolu na CSRF, a potenciálně útočníkovi umožňuje násilně odhlašovat uživatele z aplikace.

if ( logout )
   session_destroy(); // destroy all data in session

Ničit vypršelá SID editovat

Toto jednoduché opatření zvyšuje zabezpečení proti neoprávněnému přístupu k sezení, které bylo volně zanecháno. Pro realizaci je potřeba ukládat poslední čas přístupu k sezení. Když je SID znovu použito, zkontroluje se rozdíl času a pokud je rozdíl větší než povolená hodnota, sezení se zničí, jinak se nastaví nová hodnota času posledního přístupu.

Zničení sezení pokud je podezřelá vstupní stránka editovat

Pokud navštěvujete stránku, většina prohlížečů předá hodnotu referrer - stránku obsahují odkaz, ze které jste se na aktuální stránku dostali.

Pokud se tedy uživatel dostane na stránku, u které není pravděpodobné, že by byla odkazována z jiného webu (bankovnictví, mail, ...), a stránka není toho typu, kde by byly uživatelé přihlášení delší dobu, uživatel by měl pocházet pouze z oné stránky.

Každá jiná návštěva by měla být brána za podezřelou. Pokud je ale původní požadavek z HTTPS stránky, referrer se nepředává, tudíž se na toto zabezpečení nelze spoléhat.

Pro příklad stránka http://vulnerable.example.com/ může použít tuto kontrolu:

if (strpos($_SERVER['HTTP_REFERER'], 'http://vulnerable.example.com/') !== 0) {
   session_destroy(); // destroy all data in session
}
session_regenerate_id(); // generate a new session identifier

Ověřit zda jsou přídavná data v sezení konzistentní editovat

Další možnost jak vylepšit zabezpečení je ujistit se že data (například verze prohlížeče) klienta patří stejnému uživateli. Toto opatření dělá tento a další útoky o něco těžší.

Jelikož se čím dál více sítí drží RFC 3704 a dalších anti-spoofing opatření, IP adresa se stává spolehlivým identifikátorem. Zabezpečení webové stránky může být vylepšeno ověřováním konzistence IP adresy v průběhu sezení.

Toto ověřování může vypadat například takto:

if($_SERVER['REMOTE_ADDR'] != $_SESSION['PREV_REMOTEADDR']) {
   session_destroy(); // destroy all data in session
}
session_regenerate_id(); // generate a new session identifier
$_SESSION['PREV_REMOTEADDR'] = $_SERVER['REMOTE_ADDR'];

Před použitím je potřeba zvážit tyto body:

  • Několik uživatelů může sdílet stejnou IPv4 adresu. Je běžné, že jedna budova nebo zákazníci malých lokálních operátorů sdílí jednu adresu.
  • Uživatel může v průběhu času měnit IP adresu, platí to například pro uživatele na proxy síti nebo v delším časovém horizontu pro uživatele s nestatickou IP adresou. Platí to také pro uživatele mobilního internetu.

User Agent editovat

Webové prohlížeče se identifikují pomocí HTTP hlavičky "User-agent". Tato hlavička se v normálním případě nemění, pokud se tak stane, je to velmi podezřelé. Webová aplikace se může pokusit o identifikaci pomocí této hlavičky aby zabránila zlomyslným uživatelům v kradení sezení. Toto se dá ale velmi jednoduše obejít pokud útočník zaznamená řetězec user-agent oběti a poté napodobí během útoku. Toto řešení spoléhá na systému "security through obscurity".

if ($_SERVER['HTTP_USER_AGENT'] != $_SESSION['PREV_USERAGENT']) {
   session_destroy(); // destroy all data in session
}
session_regenerate_id(); // generate a new session identifier
$_SESSION['PREV_USERAGENT'] = $_SERVER['HTTP_USER_AGENT'];

Body na zvážení při implementaci:

  • Mnoho uživatelů může mít stejnou hlavičku user-agent, zneužít toho lze například v internetové kavárně nebo pokud známe výchozí prohlížeč platformy kterou uživatel používá.
  • Některé prohlížeče umožňují uživatelům měnit hlavičku user-agent za běhu, například Maxthon nebo Internet Explorer mají takzvaný "mód kompatibility", následující user-agent hlavičky může mít jediný uživatel:
    • Mozilla/5.0 (Linux; U; Android 2.2; en-us; DROID2 Build/VZW) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 854X480 motorola DROID2
    • Mozilla/5.0 (Linux; U; Android 2.2; en-us; DROID2 Build/VZW) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 480X854 motorola DROID2
    • Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
    • Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
    • Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6 (FlipboardProxy/0.0.5; +http://flipboard.com/browserproxy[nedostupný zdroj])
    • Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6 (FlipboardProxy/1.1; +http://flipboard.com/browserproxy[nedostupný zdroj])

Hloubková ochrana editovat

Pro nejvyšší ochranu je vhodné kombinovat některé z uvedených opatření. Zatímco jednu ochranu může být lehké překonat, vhodnou kombinací lze docílit dobrého zabezpečení.

Taková ochrana může obsahovat:

  • Povolení HTTPS
  • Upravit konfiguraci (nepovolovat cizí SID, nastavení time-outu, ...)
  • Regenerace sezení, podpora odhlášení, ...

Je potřeba poznamenat že HTTP hlavička referrer není předána při použití SSL.

Následující skript demonstruje několik takových opatření pro dosažení hloubkové ochrany:

if (isset($_GET['LOGOUT']) ||
$_SERVER['REMOTE_ADDR'] !== $_SESSION['PREV_REMOTEADDR'] ||
$_SERVER['HTTP_USER_AGENT'] !== $_SESSION['PREV_USERAGENT'])
session_destroy();

session_regenerate_id(); // generate a new session identifier

$_SESSION['PREV_USERAGENT'] = $_SERVER['HTTP_USER_AGENT'];
$_SESSION['PREV_REMOTEADDR'] = $_SERVER['REMOTE_ADDR'];

Všimněte si že tento kód kontroluje aktuální IP adresu (REMOTE_ADDR) a hlavičku user-agent a porovnává je z hodnotami z předchozího požadavku. To může být nevhodné kvůli některým důvodům uvedeným výše.

Reference editovat

V tomto článku byl použit překlad textu z článku Session fixation na anglické Wikipedii.