Добре, има два отделни, но свързани проблема и всеки се третира по различен начин.
Фиксиране на сесия
Това е мястото, където нападателят изрично задава идентификатора на сесията за даден потребител. Обикновено в PHP това се прави, като им се даде url като http://www.example.com/index...?session_name=sessionid
. След като атакуващият даде URL адреса на клиента, атаката е същата като атака за отвличане на сесия.
Има няколко начина за предотвратяване на фиксирането на сесия (направете всички):
Задайте session.use_trans_sid = 0
във вашия php.ini
файл. Това ще каже на PHP да не включва идентификатора в URL адреса и да не чете URL адреса за идентификатори.
Задайте session.use_only_cookies = 1
във вашия php.ini
файл. Това ще каже на PHP никога да не използва URL адреси с идентификатори на сесии.
Генерирайте отново идентификатора на сесията всеки път, когато състоянието на сесията се промени. Това означава някое от следните:
- User authentication
- Съхраняване на чувствителна информация в сесията
- Промяна на нещо относно сесията
- и т.н...
Отвличане на сесия
Това е мястото, където нападателят получава идентификатор на сесия и може да изпраща заявки, сякаш е този потребител. Това означава, че тъй като нападателят има идентификатора, те са почти неразличими от валидния потребител по отношение на сървъра.
Не можете директно да предотвратите отвличането на сесия. Можете обаче да поставите стъпки, за да го направите много трудно и по-трудно за използване.
Използвайте силен хеш идентификатор на сесията: session.hash_function
в php.ini
. Ако PHP ‹ 5.3, задайте го на session.hash_function = 1
за SHA1. Ако PHP >= 5.3, задайте го на session.hash_function = sha256
или session.hash_function = sha512
.
Изпратете силен хеш: session.hash_bits_per_character
в php.ini
. Задайте това на session.hash_bits_per_character = 5
. Въпреки че това не го прави по-трудно за кракване, има значение, когато атакуващият се опита да отгатне идентификатора на сесията. ID ще бъде по-кратък, но ще използва повече знаци.
Задайте допълнителна ентропия с session.entropy_file
и session.entropy_length
във вашия php.ini
файл. Задайте първото на session.entropy_file = /dev/urandom
, а второто на броя байтове, които ще бъдат прочетени от ентропийния файл, например session.entropy_length = 256
.
Променете името на сесията от PHPSESSID по подразбиране. Това се постига чрез извикване на session_name()
с вашето собствено име на идентификатор като първи параметър преди извикването session_start
.
Ако наистина сте параноик, можете също да завъртите името на сесията, но внимавайте, че всички сесии автоматично ще бъдат анулирани, ако промените това (например, ако го направите зависимо от часа). Но в зависимост от вашия случай на употреба, това може да е опция...
Редувайте често идентификатора на вашата сесия. Не бих направил това при всяка заявка (освен ако наистина не се нуждаете от това ниво на сигурност), но на произволен интервал. Искате да променяте това често, тъй като ако нападател отвлече сесия, не искате той да може да я използва твърде дълго.
Включете потребителския агент от $_SERVER['HTTP_USER_AGENT']
в сесията. По принцип, когато сесията започне, запазете я в нещо като $_SESSION['user_agent']
. След това при всяка следваща заявка проверявайте дали съвпада. Имайте предвид, че това може да бъде фалшифицирано, така че да не е 100% надеждно, но е по-добре, отколкото не.
Включете IP адреса на потребителя от $_SERVER['REMOTE_ADDR']
в сесията. По принцип, когато сесията започне, запазете я в нещо като $_SESSION['remote_ip']
. Това може да е проблематично от някои интернет доставчици, които използват множество IP адреси за своите потребители (като AOL преди). Но ако го използвате, ще бъде много по-сигурно. Единственият начин нападателят да фалшифицира IP адреса е да компрометира мрежата в някакъв момент между истинския потребител и вас. И ако компрометират мрежата, те могат да направят много по-лошо от отвличане (като MITM атаки и т.н.).
Включете токен в сесията и от страната на браузърите, който увеличавате и сравнявате често. По принцип за всяка заявка направете $_SESSION['counter']++
от страната на сървъра. Също така направете нещо в JS от страната на браузърите, за да направите същото (използвайки локално хранилище). След това, когато изпратите заявка, просто вземете еднократен номер от токен и проверете дали еднократният номер е същият на сървъра. Правейки това, трябва да сте в състояние да откриете отвлечена сесия, тъй като нападателят няма да разполага с точния брояч, или ако го има, ще имате 2 системи, предаващи един и същ брой и можете да кажете, че едната е фалшифицирана. Това няма да работи за всички приложения, но е един от начините за справяне с проблема.
Бележка за двете
Разликата между фиксирането на сесията и отвличането е само в това как идентификаторът на сесията е компрометиран. При фиксиране идентификаторът се задава на стойност, която нападателят знае предварително. При Hijacking е или познато, или откраднато от потребителя. В противен случай ефектите от двете са еднакви, след като идентификаторът е компрометиран.
Регенериране на идентификатор на сесия
Всеки път, когато генерирате повторно идентификатора на сесията с помощта на session_regenerate_id
старата сесия трябва да бъде изтрита. Това се случва прозрачно с манипулатора на основната сесия. Въпреки това, някои манипулатори на персонализирани сесии, използващи session_set_save_handler()
, не правят това и са отворени за атака на стари идентификатори на сесии. Уверете се, че ако използвате персонализиран манипулатор на сесии, че следите идентификатора, който отваряте, и ако не е същият, който запазвате, че изрично изтривате (или променяте) идентификатора на стария.
Използвайки манипулатора на сесията по подразбиране, можете просто да извикате session_regenerate_id(true)
. Това ще премахне старата информация за сесията вместо вас. Старият идентификатор вече не е валиден и ще доведе до създаване на нова сесия, ако атакуващият (или някой друг по този въпрос) се опита да го използва. Все пак внимавайте с манипулаторите на персонализирани сесии....
Унищожаване на сесия
Ако ще унищожите сесия (при излизане например), уверете се, че сте я унищожили напълно. Това включва премахване на бисквитката. Използвайки session_destroy
:
function destroySession() {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
session_destroy();
}
person
ircmaxell
schedule
22.02.2011