Фіксація / викрадення сеансу PHP


145

Я намагаюся зрозуміти більше про виправлення та викрадення сеансів PHP та про те, як запобігти цим проблемам. Я читав наступні дві статті на веб-сайті Кріса Шифлетта:

Однак я не впевнений, що я все розумію правильно.

Щоб запобігти фіксації сеансу, достатньо зателефонувати session_regenerate_id (true); після успішного входу в систему когось? Я думаю, що я це правильно розумію.

Він також розповідає про використання маркерів, переданих у URL-адресах через $ _GET для запобігання викрадення сеансу. Як би це було зроблено саме? Я здогадуюсь, коли хтось входить у вас, генерує ваш маркер і зберігає його у змінній сеансу, то на кожній сторінці ви порівняєте цю змінну сеансу зі значенням змінної $ _GET?

Чи потрібно міняти цей маркер лише один раз за сеанс або на кожній завантаженні сторінки?

Це також хороший спосіб запобігання викрадення без необхідності передавати значення в URL-адресах? це було б набагато простіше.


Можливо, ви можете додати посилання на сторінки, де ви знайшли ці рекомендації.
Gumbo

Відповіді:


219

Гаразд, є дві окремі, але пов'язані з цим проблеми, і кожну вирішують по-різному.

Фіксація сесії

Тут зловмисник явно встановлює ідентифікатор сеансу для сеансу для користувача. Як правило, в 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_functionin 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();
}

4
Використання 5 замість 4 біт на символ ні в якому разі не змінює "силу" (що б "сила" не означала в цьому випадку). Але хоча ваші бали доцільно загалом, у них відсутні деякі важливі деталі. Наприклад, що відбувається з сеансом, пов’язаним зі старим ідентифікатором сеансу, або як слід обробляти сеанс зі старим ідентифікатором сеансу після його недійсного.
Gumbo

2
@battal: Ні, в цьому справа. session_regenerate_idне визнає недійсним сеанс, який все ще пов'язаний зі старим ідентифікатором; лише якщо для параметра delete_old_session встановлено значення true, сеанс буде знищений. Але що робити, якщо зловмисник ініціював відновлення цього ідентифікатора?
Гумбо

6
Я не погоджуюся з відновленням сеансу щоразу, коли ви змінюєте змінну сеансу, це слід робити лише під час входу / виходу. Також перевірити користувацький агент безглуздо і перевірити REMOTE_ADDR є проблематичним. Я хотів би додати одну річ session.entropy_file = /dev/urandom. Внутрішня генерація ентропії PHP виявилася надзвичайно слабкою, і пул ентропії, який надає / dev / random або / dev / urano, - найкраще, що можна отримати на веб-сервері без апаратних програм.
грак

4
Також слід додати session.cookie_httponlyі session.cookie_secure. Перший допомагає зірвати xss (але він не ідеальний). 2-й - найкращий спосіб зупинити OWASP A9 ...
грак

4
Не розумієте такої чудової відповіді, але пропускаєте найбільш імпортний фрагмент: використовуйте SSL / HTTPS. Приріст лічильника є джерелом проблеми з багаторазовим запитом швидко один за одним, користувач оновлює сторінку двічі або двічі натискає кнопки для надсилання. Рішення IP-адреси сьогодні є проблемою для всіх користувачів мобільних пристроїв і постійно змінюють IP-адреси. Ви можете подивитися перший набір IP-адреси, але все-таки це вимагає неприємностей. Найкраще - це запобігання виявленню ідентифікатора сеансу в першу чергу, а це використання SSL / HTTPS.
Sanne

37

Обидві атаки сеансу мають одну мету: отримати доступ до законного сеансу іншого користувача. Але вектори атаки різні:

  • Під час атаки виправлення сесії зловмисник вже має доступ до дійсного сеансу і намагається змусити жертву використовувати саме цей сеанс.

  • Під час нападу викрадення сеансу зловмисник намагається отримати посвідчення сесії жертви, щоб використовувати його / її сеанс.

В обох атаках ідентифікатор сеансу є чутливими даними, на яких зосереджена ця атака. Отже, це ідентифікатор сеансу, який потрібно захистити як для доступу до читання (викрадення сесії), так і для запису (фіксація сесії).

Загальне правило захисту конфіденційних даних за допомогою HTTPS застосовується і в цьому випадку. Крім того, слід зробити наступне:

Щоб запобігти атакам виправлення сеансу , переконайтесь, що:

  • ідентифікатор сеансу приймається лише з файлу cookie (встановити session.use_only_cookies на true) і зробити його для HTTPS лише, якщо можливо (встановити session.cookie_secure на true); ви можете зробити і те, і інше session_set_cookie_params.

Щоб запобігти атакам викрадення сесії , переконайтесь, що:

Щоб запобігти обом сеансовим атакам, переконайтесь, що:

  • приймати лише сеанси, розпочаті вашою заявкою. Це можна зробити, знявши дактилоскопічний сеанс на ініціацію з конкретною інформацією про клієнта. Ви можете використовувати ідентифікатор User-Agent, але не використовувати віддалену IP-адресу або будь-яку іншу інформацію, яка може змінюватися між запитами.
  • змінити ідентифікатор сеансу за session_regenerate_id(true)допомогою спроби аутентифікації ( trueлише після успіху) або зміни привілеїв та знищити старий сеанс. (Переконайтеся, що ви зберігаєте будь-які зміни $_SESSIONвикористання session_write_close перед відновленням ідентифікатора, якщо ви хочете зберегти сеанс, пов’язаний зі старим ідентифікатором; інакше ці зміни впливатимуть лише на сеанс з новим ідентифікатором.)
  • використовувати належну реалізацію терміну дії сеансу (див. Як я можу закінчити сеанс PHP через 30 хвилин? ).

Дивовижний пост, особливо останній розділ.
Меттіс

6

Маркери, про які ви згадуєте, - це "ніколи" - номер, що використовується колись. Їх не обов'язково використовувати лише один раз, але чим довше вони використовуються, тим вище шанси на те, що не можна захопити і використати для викрадення сеансу.

Ще один недолік до нікчемності полягає в тому, що дуже важко побудувати систему, яка їх використовує і дозволяє кілька паралельних вікон в одній формі. наприклад, користувач відкриває два вікна на форумі і починає працювати над двома повідомленнями:

window 'A' loads first and gets nonce 'P'
window 'B' loads second and gets nonce 'Q'

Якщо у вас немає можливості відстежувати декілька вікон, ви збережете лише одне - вікно B / Q. Коли користувач подає свою публікацію з вікна A і пропускає не "P", система буде відхиляти публікацію як P != Q.


Отже, що це стосується фіксації сеансу?
грак

2
Він має дійсну точку, особливо в царині використання багатьох запитів AJAX одночасно.
DanielG

2

Я не читав статті Шифлетта, але, думаю, ви щось неправильно зрозуміли.

За замовчуванням PHP передає маркер сеансу в URL, коли клієнт не приймає файли cookie. Інакше в найпоширенішому випадку маркер сеансу зберігається як файл cookie.

Це означає, що якщо ви введете маркер сеансу в URL PHP, він розпізнає його і спробує використовувати його згодом. Виправлення сеансу відбувається, коли хтось створює сеанс, а потім підманлює іншого користувача поділитися тим же сеансом, відкривши URL-адресу, що містить маркер сеансу. Якщо користувач якимось чином засвідчує автентифікацію, зловмисний користувач знає маркер сеансу аутентифікованого, який може мати різні привілеї.

Як я впевнений, пояснює Шифлет, звичайне, що потрібно робити - це відновлювати інший маркер щоразу, коли привілеї користувача змінюються.


Щоб додати до цього, будь ласка, не забудьте знищити будь-які раніше відкриті сеанси, оскільки вони все ще будуть дійсні з наявними дозволами користувача.
corrodedmonkee

0

Так, ви можете запобігти фіксації сеансу, відновивши ідентифікатор сеансу один раз після входу. Таким чином, якщо зловмисник не дізнається значення файлу cookie для нещодавно підтвердженого сеансу. Інший підхід, який повністю зупиняє проблему, встановлений session.use_only_cookies=Trueу вашій конфігурації виконання. Зловмисник не може встановити значення файлу cookie в контексті іншого домену. Фіксація сеансу залежить від надсилання значення файлу cookie як GET або POST.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.