C, PHP, VB, .NET

Дневникът на Филип Петров


* Фиксиране на потребителски сесии

Публикувано на 14 ноември 2008 в раздел ОСУП.

В тази статия се засяга проблема с фиксиране на потребителски сесии при интернет базирани приложения. Този материал е превод на статията на Mitja Kolsek от acrossecurity.com, която достатъчно подробно описва теорeтичната част на проблема. В последствие в допълнителни статии ще добавим и конкретни практически примери за защита срещу този род атаки.

Почти всички интернет приложения използват потребителски сесии, за да създават по-персонализирана среда на своя уеб сайт. Сесията на всеки отделен потребител се съхранява и управлява на сървъра чрез уникален идентификационен номер (session ID). Точно тези идентификатори са често основна цел на атакуващите, които чрез тях могат да "откраднат самоличността" на потребител. Повечето сървъри вече имат изградени защити или поне добри съвети за практики за предпазване на тези ключове, главно от три класа атаки:
- Подслушване - вариант при който се извършва т.нар. session hijacking от злонамерен човек подслушващ трафика между клиент и сървър. Ще бъде разгледана по-подробно в следваща статия свързана с криптирането на комуникацията между клиент и сървър.
- Предсказнане - вече остаряла, но не задължително неработеща, техника за намиране на session id на друг потребител на базата на статистика. Днешните сървъри поддържат достатъчно дълги ключове със сравнително надеждни алгоритми за генериране.
- Налучкване - известни още като Brute Force атаки. При защитата потребителските session id от страна на сървъра може да приемем, че съвременните уеб сървъри са достатъчно надеждни срещу такъв род атаки.

В настоящата статия ние ще се спрем по-подробно на друг вид атака - фиксиране на потребителската сесия. Чрез този клас атаки "хакера" фиксира потребителското session id, още преди потребителя да е достъпил до сървъра, като по този начин си спестява проблемите по открадване на потребителския ключ по-късно. Ще разгледаме няколко метода за фиксиране на потребителски ключ - чрез аргументи в URL, чрез скрити полета на форми и чрез cookies. Естествено ще дадем и съвети за предпазване от такива атаки.

1. Въведение в потребителски сесии:

HTTP е протокол за комуникация, в който не се съхранява текущото състояние на връзката. За въвеждане на такава функционалност са измислени потребителските сесии. Базовата идея е сървъра да генерира вече споменатите идентификационни номера/ключове в някой от ранните моменти на взаимоотношение с потребителя. Сървъра изпраща към браузера на потребителя тези ключове и при нова заявка от потребителя очаква да му бъде "върнат" същия session id. По този начин session id са се превърнали и в идентификационен признак за потребителите, като приложенията ги използват, за да запазват допълнителна информация за потребителя (обикновено променливи) и създават усещане за индивидуалност в потребителите. Както споменахме има три основни начина за ръководене на сесии - чрез променливи в URL, чрез скрити полета във форми и чрез cookies. Всеки от методите има както предимства, така и недостатъци, но в крайна сметка cookies са се доказали като най-сигурен и най-удобен начин от трите. Може да се каже, че всички познати видове атаки срещу cookie-базирани сесии могат да бъдат приложени и срещу другите два типа за ръководене на сесия. Обратното обаче не е вярно.

Поради относителната сигурност много често session ID се използват като метод за автентикация. Това позволява гъвкавост на приложенията, така че да не питаме потребителя непрекъснато за име и парола, дигитален сертификат или друг тип проверка на самоличност, а вместо това да стартираме уникална потребителска сесия и да я използваме като автентикатция след първото му успешно влизане в системата. Така session IDs се превръщат в нещо като временни пароли за достъп до системата. Поради тази причина те са много апетитна информация за хакерите - на практика позволяват директен достъп до системата чрез чужд профил.

2. Фиксиране на сесии

При атаката от тип "фиксиране на потребителка сесия", атакуващият цели да накара потребителя сам да накара сървъра да използва конкретен session ID, вместо автоматично генерираният от сървъра. Нека погледнем един пример, в който сървърът online.worldbank.dom съдържа информация за банковата сметка на потребители. В този пример session ID се пренася от браузера към сървъра чрез аргумент в URL:

Фиксиране на session id
Фиксиране на session id

Първо атакуващият (в случая също легитимен потребител на системата) се автентикира на сървъра (1) и получава дадено session ID (2). След това атакуващия изпраща връзката http://online.worldbank.dom/login.jsp?sessionid=1234 към потребителя, опитвайки се да го накара да я последва (3). Потребителя последва връзката и отива на страницата за въвеждане на име и парола на сървъра (4). В този момент сървъра вижда, че потребителя вече е стартирал потребителска сесия и няма нужда от създаване на нова. Накрая потребителят предава името и паролата си към скрипта за автентикация и сървърът му дава права за достъп до личния му банков акаунт. В този момент атакуващия, знаейки неговото session ID, има достъп до личните данни на клиента (6). В този момент казваме, че потребителят е "проникнал в сесията на атакуващия".

Този пример е възможно най-простият и възможно най-лесният за предотвратяване. На първо място проблем на атакуващия, е че той трябва да е легитимен потребител на системата. На второ място той трябва да накара потребителя да последва именно неговата връзка (за нещастие обаче повечето начинаещи интернет потребители нямат никаква представа за подобни пробиви в сигурността на данните им). Естествено има доста по-сложни методи, при които е значително по-трудно атакуващия да бъде открит и да бъде предотвратено фиксирането на сесията.

Нека първо разгледаме подробно процеса за изграждане на модел на атаката. Обикновено това тя се случва на три етапа:
а. Инициализация на сесия: атакуващия създава сесия "капан", чието session ID ще се опита да предаде на потребител.
б. Фиксиране на сесия на потребител: атакуващият успява да накара потребителя да използва сесията "капан".
в. Влизане в потребителския профил на сървъра: крайната цел на атаката.

3. Инициализирация на сесия от атакуващият

Можем да класифицираме управлението на сесии от страна на сървърите в два класа:
а. Разрешителен: сървърът позволява на потребителя да избира сам своето session ID, ако такова не съществува.
б. Стриктен: Позволява използването само на познати session ID, без възможност на потребителя да ги създава.

При разрешителния режим (който се използва от не-малко сървъри като например PHP и Macromedia JRun) атакуващия до известна степен е облекчен, защото няма нужда предварително да създава потребителска сесия. Когато клиентът се свърже със сървъра, той явно указва с какво session ID иска да работи и сървъра го приема на доверие.

При стриктния режим (например Microsoft Internet Information Server) атакуващият трябва да инициализира сесия предварително. Важно е освен това да поддържа сесията активна достатъчно дълго време (обикновено сървърите прекратяват неактивните сесии след определен интервал от време). Някои сървъри имат и настройки за прекратяване на сесия автоматично след даден интервал от време, независимо дали е активна или не. Това за съжаление не винаги е практично и се използва рядко.

4. Фиксиране на конкретна сесия при потребител

Вече споменахме за трите налични метода. Ще ги разгледаме един по един:

а. Чрез URL: вече разгледан от първият пример - атакуващият изпраща конкретен URL, съдържащ sessionid до потребителя http://online.worldbank.dom/login.jsp?session=1234. Този метод е доста непрактичен, защото е лесно откриваем. Ако приложението, качено на сървъра, обаче не предложи ефикасна софтуерна защита - този метод определено ще работи. Много малки проекти пренебрегват този род защита.

б. Чрез скрито поле във форма: чрез такъв тип атака обикновено атакуващият използва свой сайт, от който пренасочва потребителя към формата на сървъра. Този модел е по-трудно откриваем от миналия. Едва ли някои от вас не е виждал е-mail, който е изпратен "уж" от някоя банка и съобщава на своите потребители, че спешно трябва да променят дадена информация в своя профил. Атакуващият любезно предоставя връзка към адрес, който много прилича на истинския. В повечето случаи става дума за друг род атаки - phishing (сайт-копие на оригиналния, който цели да открадне името и паролата в собствена база данни), но не е изключено да бъде направена фиксация на сесия (например чрез скрипт фиксиращ сесия и пренасочващ към истинския сървър).

в. Използване на cookie: това е и преобладаващият механизъм за предаване на session id. За нещастие, въпреки че е значително по-защитен от предишните два, чрез него се постига най-прикритият начин за фиксиране на сесия. Атакуващият се нуждае от прикачване на cookie със собственото си session id на компютъра на потребителя. Стандартът RFC2965 се е погрижил браузърът на потребителя да приема cookie за даден домейн само и единствено от този домейн. Така бихме могли да изключим варианта сървъра на атакуващия (attacker.dom) да сложи cookie за този на истинският сървър (online.worldbank.dom). Така атакуващият е принуден да използва някой от следните методи:
- Намиране на пробив в сигурноста в браузъра или друга услуга на потребителя с цел проникване в неговата система и инсталиране на споменатото фиксирано cookie. Това обаче е по-скоро тема за защита на конкретни приложения, които са трети страни, а не част от разглеждания модел.
- Използване на client-side скрипт
- Използване на HTML таг със Set-Cookie атрибут
- Използване на Set-Cookie в HTTP response header.

Сега ще разгледаме всеки един от тези методи подробно.

5. Използване на client-side скрипт

Повечето браузъри поддържат изпълнението на скриптове като javascript или vbscript. И двата скриптови езика поддържат функционалност за записване на cookie, чрез функцията "document.cookie". Например в javascript това се прави чрез:

	document.cookie=”sessionid=1234”;

Целта на атакуващият е да намери пробив в сигурността на сървъра и да го накара от истинския домейн да запише cookie с желаното session id. Това се постига чрез добре познатият пробив в сигурноста Cross-Site Scripting. Например в по-ранните версии на Microsoft Internet Information Server това е можело да се постигне изключително лесно, без дори да се намира грешка в клиентското приложение:
http://online.worldbank.dom/<script>document.cookie="sessioni
d=1234”;</script>.idc

Макар и банален, този пример демонстрира идеята на XSS (cross-site scripting), а именно - използване на уязвимост в скрипт на сървъра с цел изпълняване на даден код на клиентската машина. Досещате се, че такива пробиви могат да се очакват от всевъзможни места.

В допълнение към предишният споменат exploit, можем да добавим и възможността, за създаване на "дълготрайни" cookies. При създаването на споменатото cookie се задава период на активност:
http://online.worldbank.dom/<script>document.cookie="sessionid=1234;%20Expires=Friday,%201-Jan-2010%2000:00:00%20GMT”;</script>.idc

Така атакуващият е сигурен, че cookie ще остане активно за достатъчно дълго време на потребителската машина. Естествено е, че тази атака ще бъде по-добре работеща на сървъри с разрешителен достъп на cookies.

Още по-добре работещ вариант са т.нар. домейн-cookies. Атрибутът domain при създаването на cookie казва, че то ще бъде валидно не само за подаденият хост, но и за всеки друг хост от този домейн. Например:
http://online.worldbank.dom/<script>document.cookie="sessionid=1234;domain=.worldbank.dom”;</script>.idc

Това е изключително "удобно" за следния сценарии:

xss атака чрез друг сървър в същия домейн
xss атака чрез друг сървър в същия домейн

Атакуващият намира XSS пробив в услуга на сървъра www.worldbank.dom, която е от същият домейн както online.worldbank.dom. Изпраща се адреса към потребителя (1), потребителя отива на дадения адрес (2) и приема cookie от www.worldbank.dom (3). Така cookie е валидно и за другият сървър online.worldbank.dom. Когато потребителят влезе в банковия си акаунт (4), атакуващият може да направи пробив (5).

6. Използване на HTML таг със Set-Cookie атрибут

Друга "неприятна" възможност на браузърите е да могат да създават cookie чрез meta таг:
<meta http-equiv=Set-Cookie content="sessionid=1234">

Важат и вече споменатите допълнителни възможности като добавяне на време за валидност и валидност за домейн. Така атакуващият просто трябва да успее да прихване трафика между някой сървър от същия домейн и потребителя и да "вмъкне" подобен meta таг в header на някоя страница. Всеки сървър, който НЕ използва криптиране на данни към потребителя е уязвим за тази атака!

В допълнение много от вече споменатите XSS пробиви могат да бъдат измолзвани за този род атака. При постигане на meta таг атака ще се постигне значително по-добър успех от споменатите методи с javascript, защото все пак браузърите на потребителя имат функционалност за блокиране на скриптове, но много рядко на meta тагове.

7. Използване на Set-Cookie в HTTP response header.

Тук се сблъскваме с различни методи за фиксиране на сесия. На първо място ще споменем т.нар. "одобрение на сесия" от страна на сървъра. Някои сървъри като JRun и доскорошните версии на PHP могат да приемат да работят със session id, подадено директно чрез параметър към съществуващ скрипт:
http://online.worldbank.dom/?jsessionid=1234

Чрез такава заявка сървъра автоматично приема, че ще работи с подаденото session id. Вече споменахме за този вид атака.

Ако атакуващият успее да проникне в някой от под-домейните на примерния сървър worldbank.dom и да качи скрипт фиксиращ сесията. Това предполага, че на един домейн работи повече от един сървър (услуга). Става ясно, че уязвимост във елементарна допълнителна услуга на даден уеб-сайт (например wap вариант на сайта) би могла да доведе до записване на cookie, което да навреди на основна услуга.

Чрез атакуване на DNS сървъра на клиента атакуващият може да се представи за истинския сървър и така да накара клиента да комуникира с него. Такава атака обикновено се използва за phishing (крадене на име и парола на потребител), но не е изключено да се използва за фиксиране на сесия с цел по-прикрито навлизане в профила на потребителя:

Атака срещу DNS сървъра на клиента
Атака срещу DNS сървъра на клиента

След като вече веднъж е фиксирал сесията на потребителя през hack.worldbank.dom (от свое IP) чрез cookie за същия домейн, то това cookie ще бъде валидно и за online.wordbank.dom.

Положението с тези атаки става още по-сложно когато си помислите за следната ситуация:
- Атакуващият "отравя" DNS сървъра на клиента, като пренасочва трафика за често използван уеб сайт (например google.com) към свой сървър. Също така пренасочва трафика за измислен хост "hack.worldbank.dom" към свое IP.
- При опит за отваряне на google.com от клиента, той попада на сървъра на атакуващия.
- След като отвори фалшивият google, клиента е пренасочен към hack.worldbank.dom (отново IP на атакуващия).
- Чрез hack.worldbank.dom атакуващия слага въпросното session cookie и незабавно пренасочва потребителя към оригиналния сайт на google.
- Сесията за worldbank.dom е фиксирана.

По този начин потребителят дори няма да разбере какво се е случило. Виждаме, че ВСЕКИ DNS сървър с уязвимост от "DNS poisoning" може да доведе до такава атака.

Най-сериозна и трудна за противодействие е атаката от тип "човек в средата" (man in the middle), където атакуващия подслушва канала между сървъра и клиента. Във всеки един момент той би могъл да изпрати HTTP header към клиента и да фиксира неговата сесия. Имайте предвид, че този проблем НЕ СЕ решава просто чрез използването на криптиран канал (например SSL). Атакуващият в случая въобще няма за цел да прочете информацията между клиента и сървъра - той просто иска да изпрати допълнителни данни към клиента. Тъй като той разполага с публичния ключ на сървъра, то няма да има проблем да направи това.

От всичко изказано до тук ви предоставяме и схема на пълният модел на атаката от тип "фиксиране на потребителска сесия":

Пълна схема на session fixation
Пълна схема на session fixation

8. Методи за противодействие

Трябва да се има предвид, че на първо място справянето с проблема "фиксирана сесия" е в самото приложение. Именно то трябва да добавя функционалност за справяне с проблема. Задължението на сървърът, където се изпълнява уеб-приложението, е да защитава session id от "открадване" (session hijacking), но не и от фиксиране. Още по-малко отговорен трябва да бъде браузъра на клиента или неговия DNS сървър. Най-общо казано приложенията, които пишем, трябва да се грижат да:

а. Приложенията ни трябва да ингорират каквото и да session id подадено от потребителя, независимо дали сървъра на който се изпълнява е с разрешителен или стриктен режим. По този начин вие категорично задавате стриктен режим на достъп до сесиите

б. Никога не създавайте сесия преди потребителят да е влязъл в системата. Така сте сигурни, че поне атакуващият е валиден потребител и евентуално ще може да бъде проследен.

в. Използвайте таймер за активност, независимо дали сървъра има такъв или не.

г. При възможност използвайте перманентен таймер за максимален "живот" на сесия.

д. Не позволявайте използването на едно и също session id за повече от един акаунт. Въпреки, че е възможно да очаквате един клиент (или едно IP) да използва повече от един акаунт, то не би било нормално да се влиза в два акаунта едновременно през една и съща сесия. Нормалната ситуация е клиента първо да излезе от единия акаунт (като се унищожи сесията) и после да генерира нова сесия при влизането във втория.

е. Ако използвате приложението във вътрешна или фиксирана мрежа - заключете сесията по IP адреса на потребителя. Едва ли бихте очаквали влизане в една и съща сесия от различни IP адреси. Този подход не е приложим за публични Интернет услуги (в по-следваща статия ще обясним защо).

ж. Заключете сесията по различни особености на потребителската машина. Това може да бъде например версията и името на браузъра (което обаче е доста предвидим и слаб отличителен белег). Много по-силен отличителен белег е публичният ключ за SSL сертификата на потребителя (но реализацията е значително по-трудна).

з. Унищожаването на сесия трябва да става на сървъра! Не трябва да се разчита единствено на изтриване на дадено cookie от браузъра на клиента.

и. Винаги предоставяйте възможност на потребителя за "изход" от системата и го насърчавайте да го използва. Така ще унищожите както текущата сесия, така и евентуални предишни, когато потребителя е забравил да излезе стандартно от системата.

Имайте предвид, че много рядко се забелязва уеб приложение, което е напълно защитено от фиксиране на потребителска сесия. Едва ли е възможно защитаването на всички текущи уязвими сайтове. Важно е обаче за бъдещите разработчици да знаят за съществуването на този проблем. В следващите няколко статии ще покажем няколко практически съвета за справяне с проблема за фиксиране на сесиите.

ОРИГИНАЛЕН ВАРИАНТ НА СТАТИЯТА НА АНГЛИЙСКИ ЕЗИК:
http://www.acrossecurity.com/papers/session_fixation.pdf

 



Добави коментар

Адресът на електронната поща няма да се публикува


*