Базові засади управління сесіями
Безпека сесії
Модуль сесії не гарантує, що сесійна інформація, що зберігається, доступна тільки користувачеві, який створив сесію. Необхідно вжити додаткових заходів щодо захисту конфіденційності сесії, ґрунтуючись на пов'язаних із нею даних.
Оцінка важливості даних, що передаються в рамках сесії, є важливою для вибору заходів щодо захисту цієї інформації; все має свою ціну і зазвичай додаткові заходи захисту призводять до погіршення зручності кінцевого користувача. Наприклад, якщо необхідно захистити користувача від найпростіших методів соціальної інженерії, слід увімкнути session.use_only_cookies. В даному випадку з боку користувача ПЗ обов'язкова підтримка cookie, інакше механізм сесій не буде працювати.
Існує кілька способів витоку існуючого ідентифікатора сесії третім особам. Наприклад, ін'єкції JavaScript, передача ідентифікатора сесії в URL, перехоплення пакетів, фізичний доступ до пристрою і т.д. Перехоплений ідентифікатор сесії дозволить третім особам отримати доступ до всіх ресурсів, пов'язаних із цією сесією. По-перше, передача ідентифікатора сесії URL. При переході на зовнішній сайт ідентифікатор сесії користувача та адреса ресурсу можуть потрапити до статистики переходів даного сайту. По-друге, при активнішій атаці можливе прослуховування мережевого трафіку зловмисником. Якщо канал передачі даних не зашифрований, ідентифікатори сесії будуть передані у вигляді простого тексту. У такому випадку рішенням є обов'язкове використання користувачів SSL/TLS при доступі до сайту. Для цього слід застосовувати HSTS.
Зауваження: Навіть HTTPS може не захистити конфіденційні дані. Наприклад, уразливості типу CRIME, BEAST можуть дозволити зловмиснику отримати доступ до даних. Багато мереж використовують проксі HTTPS MITM для аудиту. Атакуючі також можуть налаштувати такі проксі.
Неадаптивне керування сесіями
В даний час PHP використовує адаптивне керування сесіями за промовчанням. Адаптивне керування сесіями несе додаткові ризики.
Якщо session.use_strict_mode включений і обробник збереження сесії це підтримує, неініціалізоване сесійне ID відкидається і створюється новий. Це захищає від атак, які змушують користувача використовувати відомий ID. Атакуючий може розміщувати посилання або надсилати листи, які містять сесійний ID. Наприклад http://example.com/page.php?PHPSESSID=123456789 . Якщо опція session.use_trans_sid включена, то жертва відкриє сесію з цим ідентифікатором. Опція session.use_strict_mode зменшує цей ризик.
Увага
Визначений користувачем обробник збереження також може підтримувати суворий сесійний режим шляхом реалізації функції/методу перевірки коректності ідентифікатора сесії. Усі певні користувачем обробники збереження повинні його продавати.
Cookie із сесійним ID має встановлюватися із зазначенням параметрів domain, path, httponly, secure і, починаючи з PHP 7.3, атрибут SameSite. Їхня пріоритетність визначається браузерами. Спираючись на цю пріоритетність, атакуючий може встановити сесійний ID, який використовуватиметься нескінченно. Застосування session.use_only_cookies не вирішує цю проблему . session.use_strict_mode зменшує ризик . session.use_strict_mode=On, не допускає використання неініціалізованих сесійних ID.
Зауваження: Даже при уменьшении риска с помощьюsession.use_strict_mode атакуючий все ще може змусити користувача використати вже ініціалізовану сесію, створену атакуючим. Наприклад, JavaScript-ін'єкція. Ця атака може бути пом'якшена, якщо дотримуватися рекомендацій цього посібника. Якщо ви дотримуєтеся цього посібника, ви повинні включити session.use_strict_mode, використовувати управління сесіями на основі тимчасових міток та перестворювати ідентифікатор сесії за допомогою session_regenerate_id()як рекомендується. Якщо ви все це зробите, ідентифікатор сесії зловмисника буде видалено. Якщо доступ до сесії, що минув, ви повинні зберегти всі дані активних сесій користувача. Це дозволить для подальшого розслідування причин того, що сталося. Після цього примусово змусіть користувача вийти з усіх активних сесій, тобто вимагати від користувачів переавторизації. Це дозволить запобігти атакі з використанням краденої сесії.
Увага
Доступ до сесії, що минув, не завжди означає атаку. Нестабільне мережне з'єднання та/або негайне видалення активної сесії може спричинити подібну поведінку.
С PHP 7.1.0 добавлена функцияsession_create_id(). Ця функція може бути корисною для створення ідентифікатора сесії з використанням ідентифікатора користувача як префікс для досягнення більшої керованості. При її використанні дуже важливо дозволяти session.use_strict_mode. В іншому випадку, несумлінні користувачі зможуть встановлювати підроблені ідентифікатори сесій для інших користувачів.
Зауваження: У версіях PHP до 7.1.0 необхідно використовувати CSPRNG, наприклад, /dev/urandom або random_bytes() та функції хешування для генерації нового ідентифікатора сесії . session_create_id() має вбудовану функціональність виявлення колізій і генерує ідентифікатор на основі INI-налаштувань. Використання session_create_id() є кращою практикою.
Перестворення ідентифікатора сесії
Использованиеsession.use_strict_mode - Це добре, але недостатньо. Розробник також має використовувати session_regenerate_id() для забезпечення безпеки сесій.
Перестворення ідентифікаторів сесій сильно зменшує ризик крадіжки сесії, відповідно треба на періодичній основі запускати session_regenerate_id(). Наприклад, перестворювати ідентифікатор сесії кожні 15 хвилин для особливо секретних даних. Навіть якщо сесію вкрадуть, вона досить скоро стане скінченою і спроба її використовувати призведе до помилки сесії, що минув.
Ідентифікатор сесії повинен перестворюватися при підвищенні привілеїв користувача, наприклад, при аутентифікації. Функція session_regenerate_id() повинна викликатися до запису авторизаційної інформації $_SESSION. session_regenerate_id() зберігає дані поточної сесії автоматично). Переконайтеся, що поточна сесія відзначена як авторизована.
РазработчикиНЕ ПОВИННІполагаться на механизм истечения срока действия идентификатора сессии с помощьюsession.gc_maxlifetime. Атакуючі можуть періодично отримувати доступ до сесії для запобігання її терміну дії та продовжувати використовувати ідентифікатор жертви, включаючи автентифіковані сесії.
Натомість, ви повинні самостійно реалізувати управління даними сесії базуючись на тимчасовій мітці.
Увага
Незважаючи на те, що менеджер сесій може прозоро керувати тимчасовими мітками, ця функціональність не реалізована. Дані старих сесій зберігаються до запуску збирача сміття. У той же час, розробники повинні переконатися, що дані сесій, що минув, видалені. Однак розробники не повинні видаляти дані активних сесій негайно. Наприклад, ніколи не викликайте session_regenerate_id(true);
иsession_destroy() Спільно для активних сесій. Це може здатися суперечливим, але це обов'язкова вимога.
session_regenerate_id()по умолчаниюне видаляє старі сесії Застарілі авторизовані сесії можуть бути доступними для використання. Розробники повинні припинити будь-яку можливість використання старих сесій будь-ким, заборонивши доступ до сесій самостійно, використовуючи тимчасові мітки.
Увага
Негайне видалення активних сесій може спричинити небажані побічні ефекти. Сесія може перерватися через нестабільність мережі або конкурентний доступ до сайту/додатку.
Потенційний недобросовісний доступ буде неможливо відстежити та проаналізувати, якщо дані сесій негайно видалятимуться.
Замість негайного видалення старих сесій ви повинні зберігати їх нетривалий час, наприклад, встановивши спеціальний прапор та час остаточного закінчення сесії в $_SESSION, заборонивши будь-кому звертатися до цих даних.
Ви не повинні забороняти доступ до старих сесій відразу після виклику session_regenerate_id(). Потрібно почекати кілька секунд для стабільних мережних з'єднань і кілька хвилин для нестабільних, наприклад, для WiFi або мобільного інтернету.
Якщо користувач намагається отримати доступ до сесії, ви не повинні його надавати. У цьому випадку рекомендується видаляти статус "авторизований" з усіх активних сесій користувача, оскільки це дуже схоже на атаку.
session.use_only_cookiesи правильное использованиеsession_regenerate_id() можуть призвести до персональної DoS за допомогою установки cookie, що не видаляється. Якщо таке відбувається, ви можете попросити користувача видалити cookie і попередити його про можливі проблеми з безпекою. Атакуючий може встановлювати шкідливі cookie через вразливість у веб-застосунку (тобто JavaScript-ін'єкція), вразливість у браузерному плагіні і т.д.
Увага
Не недооценивайте риск DoSsession.use_strict_mode=On є обов'язковим для загальної безпеки ідентифікаторів сесій! Усі сайти повинні використовувати session.use_strict_mode
DoS (відмова в обслуговуванні) може статися лише тоді, коли обліковий запис знаходиться під атакою. Найчастіша передумова для нього – JavaScript-ін'єкція.
Видалення даних сесії
Дані сесій, що минув, повинні бути недоступні та видалені. Існуючий механізм керування сесіями робить це не дуже добре.
Дані сесій, що минув, треба видаляти так швидко, як тільки можливо. З іншого боку, дані активних сесій НЕ ПОВИННІ видалятися відразу. Для забезпечення цих суперечливих вимог, ви повинні самостійно реалізувати механізм контролю за сесіями на базі тимчасових міток.
Встановлюйте та керуйте тимчасовими мітками життя сесії через $_SESSION. Забороняйте доступ до даних сесій, що минув. Якщо ви виявили спробу доступу до даних застарілої сесії, знімайте статус авторизації з усіх активних сесій користувача і змушуйте його переавторизуватися. Доступ до даних сесії може означати атаку. Для забезпечення такої поведінки ви повинні відстежувати усі активні сесії користувача.
Зауваження: Доступ до сесії може також статися через нестабільний мережевий доступ та/або конкурентний доступ до програми/сайту. Сервер може спробувати встановити новий ідентифікатор сесії через cookie, але пакет Set-Cookie може не дійти до клієнта через поганий зв'язок. Одна сполука може викликати перестворення ідентифікатора за допомогою session_regenerate_id()а інше, в той же час, може не отримати нового ідентифікатора. Отже, ви повинні заборонити доступ до сесій трохи пізніше. Тобто управління сесіями на базі тимчасових міток є обов'язковим.
Коротше кажучи, не знищуйте дані сесії не за допомогою session_regenerate_id(), ниsession_destroy(), а використовуйте механізм доступу до сесії на базі тимчасових міток. Нехай session_gc() сам видаляє старі сесії зі сховища.
Сесії та блокування
За замовчуванням ці сесії заблоковані, щоб уникнути стану гонки. Блокування є обов'язковим для забезпечення консистентності даних сесії між запитами.
Однак блокування може бути використане атакуючим для організації DoS-атаки. Для зменшення ризику DoS з використанням блокування сесій мінімізуйте їх. Використовуйте блокування "read only", коли сесію не потрібно оновлювати. Використовуйте опцію 'read_and_close' з session_start(). . session_start(['read_and_close'=>1]);
Закривайте сесію за допомогою session_commit() відразу, як тільки ви закінчили оновлювати $_SESSION.
Текущий механизм управления сессиямине стежитьза изменениями $_SESSION, доки сесія неактивна. Це ваша зона відповідальності, стежити за тим, щоб такого не траплялося.
Активні сесії
Розробники повинні стежити за активними сесіями кожного користувача та сповіщати його, скільки є активних сесій, з яких IP (і де географічно), як довго вони активні тощо. PHP не зробить цього за вас. Ви маєте це робити.
Є кілька шляхів реалізації. Ви можете зберігати всю потрібну інформацію у спеціальній базі даних. Отже, коли сесія буде видалена збирачем сміття, ви повинні це відслідковувати та відповідно оновлювати свою базу даних.
Найпростіший спосіб - використовувати ідентифікатор користувача як префікс для ідентифікатора сесії та зберігати всю необхідну інформацію в $_SESSION. Багато баз даних вміють досить швидко вибирати рядки префіксу. Ви можете використовувати session_regenerate_id() і session_create_id() для цього.
Увага
Ніколи не використовуйте конфіденційні дані як префікс. Якщо ідентифікатор користувача є конфіденційним, розгляньте можливість використання функції hash_hmac()
Увага
Для подібного налаштування потрібно увімкнення session.use_strict_mode. Переконайтеся, що ця опція увімкнена, інакше база даних активних сесій може бути скомпрометована.
Управління сесіями з урахуванням тимчасових міток є обов'язковим визначення застарілих сесій. Якщо ви виявили спробу доступу до застарілої сесії, необхідно скинути прапори авторизації для всіх активних сесій користувача.
Сесії та автоматичний вхід
Розробники НЕ ПОВИННІ використовувати довгоживучі сесії для реалізації автоматичного входу в систему, тому що це різко підвищує ймовірність крадіжки сесії. Автоматичний вхід до системи повинен реалізовуватись розробником самостійно.
Встановлюйте безпечні хешовані одноразові ключі як ключі автологіну за допомогою setcookie(). Використовуйте безпечне хешування, сильніше ніж SHA-2, наприклад, SHA-256 або вище з випадковими даними з random_bytes()или /dev/urandom.
Якщо користувач не авторизований, перевірте, чи коректний одноразовий ключ автологіну. Якщо ключ коректний, авторизуйте користувача та встановіть новий одноразовий ключ. Ключ автологіна обов'язково має бути одноразовим, тобто ніколи не використовуйте його повторно, а завжди створюйте новий.
Ключ автологіна – це дуже довгоживучий ключ авторизації. Його треба захищати максимум. Використовуйте параметри path/httponly/secure/SameSite під час встановлення cookie для захисту. Ніколи не передавайте ключ автологіна, крім випадків, коли це потрібно.
Розробник повинен реалізувати функціонал, який відключає автоматичний вхід до системи та видаляє непотрібні "cookie", встановлені для його реалізації.
CSRF (Міжсайтова підробка запиту)
Сесії та авторизація не захищають від атак типу CSRF. Розробники мають самостійно реалізовувати захист.
output_add_rewrite_var() може бути використана для захисту від CSRF. Читайте посібник для деталей.
Зауваження: До PHP 7.2.0 використовувався один і той же буфер виводу та INI-налаштування для "trans sid". Так що використання output_add_rewrite_var() з PHP попередніх версій не рекомендується.
Багато кадрів підтримують захист від CSRF. Для отримання докладнішої інформації зверніться до документації фреймворку.
Починаючи з PHP 7.3, для сесійної cookie можна встановити атрибут SameSite. Це забезпечить додатковий захист проти CSRF.