Безпека сеансу PHP


125

Які рекомендації щодо забезпечення безпеки відповідальної сесії за допомогою PHP? Інформація є в усьому Інтернеті, і саме час приземлитися в одному місці!

Відповіді:


88

Щоб захистити сеанс, потрібно виконати декілька дій:

  1. Використовуйте SSL під час автентифікації користувачів або виконання чутливих операцій.
  2. Відновлюйте ідентифікатор сеансу щоразу, коли рівень безпеки (наприклад, вхід у систему) змінюється. Ви навіть можете відновити ідентифікатор сеансу кожен запит, якщо хочете.
  3. Замовчуйте час на сеанси
  4. Не використовуйте глобальні регістри
  5. Зберігайте дані автентифікації на сервері. Тобто не надсилайте у файлі cookie реквізити, такі як ім’я користувача.
  6. Перевірте $_SERVER['HTTP_USER_AGENT']. Це додає невеликий бар'єр для викрадення сеансів. Ви також можете перевірити IP-адресу. Але це спричиняє проблеми для користувачів, які змінюють IP-адресу через балансування навантаження в декількох підключеннях до Інтернету тощо (що в нашому середовищі тут).
  7. Блокуйте доступ до сеансів у файловій системі або використовуйте користувальницьку обробку сеансу
  8. Для чутливих операцій слід розглянути необхідність повторного надання користувачам даних, що ввійшли в систему

15
Використання SSL лише для деяких операцій недостатньо, якщо ви не маєте окремих сеансів для зашифрованого та незашифрованого трафіку. Якщо ви використовуєте один сеанс через HTTPS і HTTP, зловмисник викраде його на перший запит, який не є HTTPS.
Корнель

6
-1 агент користувача тривіально підробляє. Те, що ви описуєте код відходів, не є системою безпеки.
грак

24
@ The Rook, це може бути тривіальним бар'єром (зловмисник може захопити користувача-агента жертви за допомогою власного веб-сайту) і покладається на безпеку через незрозумілість, але це все ще один додатковий бар'єр. Якщо HTTP-User-Agent повинен був змінитися під час використання сеансу, це було б вкрай підозрілою і, швидше за все, атакою. Я ніколи не казав, що ти можеш використовувати це поодинці. Якщо ви поєднуєте це з іншими методами, у вас є набагато більш безпечний сайт.
grom

5
@ grom Я думаю, що це як покласти шматочок скотча через вашу двері і сказати, що це заважатиме людям вриватися.
Грак

8
Якщо ви перевіряєте агент користувача, ви блокуєте всі запити користувачів IE8, коли вони перемикають режим сумісності. Дивіться, як мені було цікаво відстежувати цю проблему у власному коді: serverfault.com/questions/200018/http-302-problem-on-ie7 . Я беру користувальницьку перевірку, тому що це така банальна штукатурка, як казали інші.
відповідність

15

Одне правило - викликати session_regenerate_id кожного разу, коли рівень безпеки сеансу змінюється. Це допомагає запобігти викрадення сеансу.


11

Мої два (або більше) копійок:

  • Нікому не довіряй
  • Фільтр-вхід, вихідний вихід (cookie, дані сеансу - це також ваші дані)
  • Уникайте XSS (тримайте HTML добре сформованим, погляньте на PHPTAL або HTMLPurifier )
  • Оборона в глибину
  • Не піддавайте дані

На цю тему є крихітна, але хороша книга: Основна безпека PHP Кріса Шифлетта .

Основна безпека PHP http://shiflett.org/images/essential-php-security-small.png

На домашній сторінці книги ви знайдете кілька цікавих прикладів коду та зразки розділів.

Ви можете використовувати техніку, згадану вище (IP та UserAgent), описану тут: Як уникнути крадіжки особистих даних


+1 для профілактики XSS. Без цього неможливо захистити від CSRF, і, таким чином, хтось може "проїхати" сеанс, навіть не отримавши ідентифікатор сесії.
Корнель

11

Я думаю, що однією з головних проблем (яка вирішується в PHP 6) є register_globals. На даний момент одним із стандартних методів, що використовується для уникнення, register_globalsє використання $_REQUEST, $_GETабо $_POSTмасиви.

"Правильний" спосіб зробити це (станом на 5.2, хоча там трохи баггі, але стабільний станом на 6, який найближчим часом) - через фільтри .

Тож замість:

$username = $_POST["username"];

ви б робили:

$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);

або навіть просто:

$username = filter_input(INPUT_POST, 'username');

2
Це взагалі не стосується питання.
The Pixel Developer

5
Дійсно? Тоді чому у прийнятій відповіді вони згадують не використовувати глобальні регістри? Невже, що стосується більшості розробників заводу, зареєструвати глобалі та формувати змінну обробку не підпадає під парасольку "сеансів", навіть якщо це технічно не є об'єктом "сеансу"?
cmcculloh

9
Я згоден, це не повністю відповідає на питання, але це, безумовно, ЧАСТИНА відповіді на питання. Знову ж таки, це позначає кульову точку у прийнятій відповіді "Не використовуйте глобальні регістри". Це говорить про те, що робити замість цього.
cmcculloh


5

Використання IP-адреси насправді не найкраща ідея. Наприклад; мій офіс має дві IP-адреси, які звикають залежно від завантаження, і ми постійно стикаємося з проблемами, використовуючи IP-адреси.

Натомість я вирішив зберігати сеанси в окремій базі даних для доменів на своїх серверах. Таким чином, ніхто з файлової системи не має доступу до цієї інформації про сеанс. Це було дуже корисно для phpBB до 3.0 (вони з тих пір виправили це), але я все одно гарна ідея.


3

Це досить банально і очевидно, але не забудьте сеанс_destroy після кожного використання. Це може бути важко реалізувати, якщо користувач не виходить з явного виходу, тому для цього може бути встановлений таймер.

Ось хороший підручник із setTimer () та clearTimer ().


3

Основна проблема з PHP-сесіями та безпекою (окрім викрадення сеансу) пов'язана з тим, в якому середовищі ви знаходитесь. За замовчуванням PHP зберігає дані сеансу у файлі у тимчасовій директорії ОС. Без особливих роздумів або планування це каталог, який читається у всьому світі, тому вся інформація про сеанси є загальнодоступною для всіх, хто має доступ до сервера.

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

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


3

Я налаштовував свої сеанси так:

на сторінці входу:

$_SESSION['fingerprint'] = md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR']);

(фраза, визначена на сторінці конфігурації)

потім на заголовку, який знаходиться на решті сайту:

session_start();
if ($_SESSION['fingerprint'] != md5($_SERVER['HTTP_USER_AGENT'] . PHRASE . $_SERVER['REMOTE_ADDR'])) {       
    session_destroy();
    header('Location: http://website login page/');
    exit();     
}

3

php.ini

session.cookie_httponly = 1
change session name from default PHPSESSID

eq Apache add header:

X-XSS-Protection    1

httpd.conf -> <FilesMatch "\. (php | phtml | aspx | htm | html) $"> Набір заголовків X-XSS-Protection "1" </FilesMatch>
користувач956584

Будьте в курсі, що X-XSS-Protectionце зовсім не корисно. Насправді сам алгоритм захисту можна було експлуатувати, роблячи його гірше, ніж раніше.
Pacerier

2

Я перевірив би і IP-адресу, і Агент користувача, щоб побачити, чи не змінюються вони

if ($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']
    || $_SESSION['user_ip'] != $_SERVER['REMOTE_ADDR'])
{
    //Something fishy is going on here?
}

5
IP може законно змінюватися, якщо користувач стоїть за збалансованою навантаженням фермою проксі.
Корнель

2
І user_agent може змінюватися щоразу, коли користувач оновлює свій браузер.
scotts

3
@scotts Я погоджуюся з частиною IP, але для оновлення браузера ви б встановили сеанс, коли вони ввійдуть, щоб я не бачив, як би оновити там браузер без створення нового сеансу, як тільки вони знову ввійдуть у систему.
JasonDavis

Я вважаю, що user_agent також може змінюватися при перемиканні між сумісним режимом в IE8. Підробляти також дуже просто.

Так, але що робити з користувачами, які мали статичний IP eq GSM і змінюється кожні півгодини. Отже, зберігається IP у сесії + ім'я хоста, КОГО IP! = REMOTE_ADDR перевірити хост та порівняти еквівалент hostanmes. 12.12.12.holand.nl-> коли це holand.nl == вірно. Але деякий хост мав ім'я хоста на основі IP. Тоді потрібно порівняти маску 88.99.XX.XX
користувач956584

2

Якщо ви використовуєте session_set_save_handler (), ви можете встановити власний обробник сеансу. Наприклад, ви можете зберігати свої сеанси в базі даних. Зверніться до коментарів php.net для прикладів обробника сесії бази даних.

Сесії БД також хороші, якщо у вас є кілька серверів, інакше, якщо ви використовуєте файлові сеанси, вам слід переконатися, що кожен веб-сервер мав доступ до однієї файлової системи для читання / запису сеансів.


2

Ви повинні бути впевнені, що дані сеансу є безпечними. Переглядаючи ваш php.ini або використовуючи phpinfo (), ви можете знайти налаштування сеансу. _session.save_path_ повідомляє вам, де вони зберігаються.

Перевірте дозвіл папки та її батьків. Він не повинен бути загальнодоступним (/ tmp) або бути доступним для інших веб-сайтів на вашому спільному сервері.

Припускаючи, що ви все ще хочете використовувати сеанс php, ви можете встановити php для використання іншої папки, змінивши _session.save_path_ або збережіть дані в базі даних, змінивши _session.save_handler_.

Можливо, ви зможете встановити _session.save_path_ у своєму php.ini (деякі провайдери це дозволяють) або для apache + mod_php, у файлі .htaccess у кореневій папці вашого веб-сайту: php_value session.save_path "/home/example.com/html/session" . Ви також можете встановити його під час виконання за допомогою _session_save_path () _.

Перевірте підручник Кріса Шифлетта або Zend_Session_SaveHandler_DbTable для встановлення та альтернативного обробника сесії.

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