Гаразд, є дві окремі, але пов'язані з цим проблеми, і кожну вирішують по-різному.
Фіксація сесії
Тут зловмисник явно встановлює ідентифікатор сеансу для сеансу для користувача. Як правило, в 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-адреси з ідентифікаторами сеансу.
Відновіть ідентифікатор сеансу щоразу, коли статус сеансу зміниться. Це означає будь-що з наступного:
- Аутентифікація користувача
- Зберігання конфіденційної інформації в сеансі
- Змінюючи що-небудь про сеанс
- тощо ...
Викрадання сесії
Тут зловмисник отримує ідентифікатор сеансу і може надсилати запити так, ніби вони були цим користувачем. Це означає, що оскільки у зловмисника є ідентифікатор, вони не відрізняються від дійсного користувача щодо сервера.
Ви не можете безпосередньо запобігти викрадення сеансу. Однак ви можете вжити заходів, щоб зробити це дуже складним та складним у використанні.
Використовуйте сильний ідентифікатор хешу сеансу: session.hash_function
in 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
. Хоча це не ускладнює злому, але це має значення, коли зловмисник намагається відгадати ідентифікатор сеансу. Ідентифікатор буде коротшим, але використовуватиме більше символів.
Встановіть додаткову ентропію за допомогою 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 системи, що передають однаковий підрахунок, і можна сказати, що одна підроблена. Це не буде працювати для всіх програм, але це один із способів боротьби з проблемою.
Примітка до двох
Різниця між фіксацією сесії та викраденням полягає лише в тому, як ідентифікатор сеансу порушений. У фіксації ідентифікатору встановлюється значення, яке зловмисник знає перед рукою. У викраданні це або здогадуються, або викрадають у користувача. Інакше наслідки обох однакові, коли ідентифікатор порушений.
Відтворення ID сеансу
Щоразу, коли ви регенеруєте ідентифікатор сеансу, використовуючи session_regenerate_id
старий сеанс, слід видалити. Це відбувається прозоро з основним обробником сесії. Однак деякі користувальницькі обробники сеансів, які використовуютьsession_set_save_handler()
це, не роблять цього, і вони можуть атакувати на старі ідентифікатори сеансу. Переконайтеся, що якщо ви використовуєте користувальницький обробник сеансу, ви відстежуєте відкритий вами ідентифікатор, а якщо ви не той самий, який ви зберігаєте, ви явно видаляєте (або змінюєте) ідентифікатор на старому.
Використовуючи обробник сеансу за замовчуванням, у вас все просто, лише дзвонивши session_regenerate_id(true)
. Це видалить стару інформацію про сеанс. Старий ідентифікатор більше не дійсний і спричинить створення нового сеансу, якщо зловмисник (або хтось інший з цього питання) намагатиметься його використовувати. Будьте обережні з користувацькими обробниками сесій, хоча ....
Знищення сесії
Якщо ви збираєтеся знищити сеанс (наприклад, при виході з системи), переконайтеся, що ви його ретельно знищили. Сюди входить скасування файлу cookie. Використання session_destroy
:
function destroySession() {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
session_destroy();
}