Правда о сессиях
Страница 6. Выдача себя за другого. Часть 2
Конечно, перед этим вам необходимо сохранять MD5-хэш от полного
названия браузера пользователя всякий раз, когда вы впервые начинаете
сессию, как показано в листинге 4.
session_start ();
$_SESSION [ ‘HTTP_USER_AGENT’ ] = md5 ( $_SERVER [ ‘HTTP_USER_AGENT’ ]);
Хотя и не обязательно, чтобы вы использовали MD5-хэш вместо полного
названия браузера пользователя, это поможет обеспечить определённое
постоянство и исключить необходимость проверки правильности значения $_SERVER[‘HTTP_USER_AGENT’]
перед сохранением его в сессии. Так как данные эти берутся от клиента,
доверять им вслепую нельзя, но формат MD5-хэша независим от входных
данных.
Теперь, когда мы добавили проверку браузера пользователя,
атакующий должен осуществить два шага для того, чтобы подделать сессию:
- Получить правильный идентификатор сессии.
- Предоставить при ВСД-атаке такой же заголовок User-Agent.
Хоть это, несомненно, и возможно, по крайней мере, это сложнее, чем,
если бы второй шаг был пропущен. Таким образом, мы уже несколько
усилили безопасность сессионного механизма.
Другие заголовки могут быть добавлены таким же путём, и вы
можете даже использовать в качестве «отпечатков пальцев» комбинацию
заголовков. Если вы также добавите некий дополнительный секретный
префикс, то такие «отпечатки» становится практически невозможно
угадать. Посмотрите пример на листинге 5.
session_start ();
$fingerprint = ‘SECRETSTUFF’ . $_SERVER [ ‘HTTP_USER_AGENT’ ] . $_SERVER [ ‘HTTP_ACCEPT_CHARSET’ ];
$_SESSION [ ‘fingerprint’ ] = md5 ( $fingerprint . session_id ());
?>
Заголовок Accept не должен использоваться в «отпечатках
пальцев», так как Microsoft’овский Internet Explorer известен
расхождением в значениях этого заголовка в случаях, когда пользователь
обновляет страницу и когда он кликает по ссылке.
С трудно угадываемыми «отпечатками пальцев» некоторый выигрыш
достигается и без усложнения этой информации иным, чем
демонстрировалось до сих пор, способом. При существующем механизме для
ВСД по сути требуются те же два шага, хотя второй шаг теперь гораздо
сложнее, так как атакующий должен воспроизвести множественные
заголовки.
Для увеличения безопасности необходимо начать включать данные в
дополнение к уникальному идентификатору. Рассмотрим механизм управления
сессией, при котором уникальный идентификатор передаётся в GET-данных.
Если «отпечатки пальцев», сгенерированные в предыдущем примере, также
передаются как GET-данные, атакующий должен осуществить следующие три
шага для успешной подделки сессии:
- Получить правильный идентификатор сессии.
- Предоставить те же HTTP-заголовки.
- Предоставить правильные «отпечатки пальцев».
Если и уникальный идентификатор, и «отпечатки пальцев» передаются
как GET-данные, то, возможно, что атакующий, который сможет получить
что-то одно из них, также получит доступ и к другому. Более безопасным
подходом является использование двух различных методов передачи —
GET-данных и кук. Конечно, это зависит от пользовательских настроек, но
для тех, кто разрешил куки, может быть обеспечен дополнительный уровень
защиты. Таким образом, если атакующий получит уникальный идентификатор
через уязвимость браузера, «отпечатки пальцев», вероятно, всё ещё будут
ему неизвестны.
Есть много других способов, которые могут быть использованы,
чтобы увеличить безопасность вашего механизма управления сессией. Будем
надеяться, вы добьётесь успеха на пути создания некоторых собственных
техник. Как-никак, именно вы являетесь экспертом ваших собственных
приложений, поэтому, вооружённые хорошим пониманием сессий, вы —
самый подходящий человек для реализации дополнительной безопасности.
Защита идентификатора сессий в PHP
Безопасность веб-сайтов основывается на управлении сессиями. Когда пользователь подключается к безопасному сайту, он предоставляет учетные данные, как правило, в форме имени пользователя и пароля. Веб-сервер не имеет представления о том, какой пользователь уже вошел в систему и как он переходит от страницы к странице. Механизм сессий позволяет пользователям не вводить пароль каждый раз, когда они хотят выполнить новое действие или перейти к новой странице.
В сущности, управление сессией гарантирует, что в настоящее время соединен тот пользователь, который проходил авторизацию. Но, к сожалению, сессии стали очевидной мишенью для хакеров, поскольку они могут позволить получить доступ к веб-серверу без необходимости проверки подлинности.
После аутентификации пользователя, веб-сервер предоставляет ему идентификатор сессии. Этот идентификатор хранится в браузере и подставляется всякий раз, когда нужна проверка подлинности. Это позволяет избежать повторяющихся процессов ввода логина/пароля. Все это происходит в фоновом режиме и не доставляет дискомфорта пользователю. Представьте, если бы вы вводили имя и пароль каждый раз, когда просматривали новую страницу!
В данной статье я постараюсь изложить все известные мне способы защиты идентификатора сессии в PHP.
Использование cookie
По умолчанию вся информация о сессии, включая ID, передается в cookie. Но так бывает не всегда. Некоторые пользователи отключают cookie в своих браузерах. В таком случае браузер будет передавать идентификатор сессии в URL.
Здесь ID передается в открытом виде, в отличие от сессии через cookie, когда информация скрыта в HTTP-заголовке. Самым простым способом защиты от этого будет запрет передачи идентификатора сессии через адресную строку. Сделать это можно, прописав следующее в конфигурационном файле Apache-сервера .htaccess:
php_flag session.use_only_cookies on
Использование шифрования
Если на вашем сайте должна обрабатываться конфиденциальная информация, такая как номера кредитных карт (привет от Sony), следует использовать SSL3.0 или TSL1.0 шифрование. Для этого при установке cookie следует указывать true для параметра secure.
Если вы храните пароль сессии в переменной $_SESSION (все-таки лучше использовать sql), то не стоит хранить его в открытом виде.
if ($_SESSION['password'] == $userpass) < // код >
Приведенный выше код не безопасный, так как пароль хранится в виде обычного текста в переменной сессии. Вместо этого используйте md5-шифрование, примерно так:
if ($_SESSION['md5password'] == md5($userpass)) < // код >
Проверка браузера
Чтобы отсечь возможность использования сессии с другого браузера (компьютера), следует ввести проверку поля HTTP-заголовка user-agent:
session_start(); if (isset($_SESSION['HTTP_USER_AGENT'])) < if ($_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT'])) < // код >> else
Срок действия сессии
Ограничьте время жизни сессии, а также время действия cookie. По умолчанию срок действия сессии 1440 секунд. Изменить это значение можно через php.ini и .htaccess. Пример для .htaccess:
# Время жизни сессии в секундах
php_value session.gc_maxlifetime 3600
# Время жизни куки в секундах
php_value session.cookie_lifetime 3600
Привязка по IP-адресу
В определенных ситуациях (не всегда) следует установить привязку по IP-адресу. В основном когда количество пользователей ограничено и имеют статичные IP. Проверка может быть либо по списку разрешенных IP-адресов,
include ("ip_list.php"); //$ip_white_list = array ( 'admin1' => '111.222.333.444', 'admin2' => '555.666.777.888'); if(!empty(array_search($_SERVER['REMOTE_ADDR'],$ip_white_list))) < header("Location: admin.php"); >else
либо по IP-адресу для каждого запроса (только для статичных IP):
if(isset($_SESSION['ip']) and $_SESSION['ip'] == $_SERVER['REMOTE_ADDR']) < header("Location: admin.php"); >else
Следует осознавать, что полностью избежать взлома невозможно. Можно только максимально усложнить этот взлом любыми известными способами. Однако следует также не забывать о своих легальных пользователях, чтобы не осложнить им жизнь такой защитой.