Ответ 1
Хорошо, есть две отдельные, но связанные проблемы, и каждый из них обрабатывается по-разному.
Фиксация сеанса
Здесь злоумышленник явно задает идентификатор сеанса для пользователя. Как правило, в 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
в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 на стороне браузеров, чтобы сделать то же самое (используя локальное хранилище). Затем, когда вы отправляете запрос, просто возьмите nonce токена и убедитесь, что nonce на сервере одинаково. Делая это, вы должны иметь возможность обнаруживать захваченный сеанс, так как у злоумышленника не будет точного счетчика, или если у вас это будет, у вас будет 2 системы, передающие один и тот же счетчик и могу сказать, что он подделан. Это не будет работать для всех приложений, но это один из способов борьбы с проблемой.
Замечание о двух
Разница между Session Fixation и Hijacking заключается только в том, что скомпрометирован идентификатор сеанса. При фиксации идентификатор устанавливается в значение, которое злоумышленник знает перед собой. В угоне он либо угадал, либо украл у пользователя. В противном случае эффекты двух одинаковы при скомпрометировании идентификатора.
Регенерация идентификатора сеанса
Всякий раз, когда вы восстанавливаете идентификатор сеанса с помощью 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();
}
function destroySession() {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
session_destroy();
}