Терминология
- Пользователь: Посетитель.
- Клиент: Определенное веб-совместимое программное обеспечение, установленное на конкретном компьютере.
Понимание сеансов
Чтобы понять, как сделать сеанс безопасным, вы должны сначала понять, как сеансы работают.
Давайте посмотрим на этот кусок кода:
session_start();
Как только вы позвоните, PHP будет искать файл cookie с именем PHPSESSID
(по умолчанию). Если он не найден, он создаст его:
PHPSESSID=h8p6eoh3djplmnum2f696e4vq3
Если он найден, он принимает значение PHPSESSID
и затем загружает соответствующий сеанс. Это значение называется session_id
.
Это единственное, что клиент узнает. Все, что вы добавляете в переменную сеанса, остается на сервере и никогда не передается клиенту. Эта переменная не изменится, если вы измените содержимое $_SESSION
. Он всегда остается неизменным, пока вы не уничтожите его или не истечет время ожидания. Следовательно, бесполезно пытаться запутать содержимое $_SESSION
путем его хеширования или другими способами, поскольку клиент никогда не получает и не отправляет эту информацию.
Затем, в случае нового сеанса, вы установите переменные:
$_SESSION['user'] = 'someuser';
Клиент никогда не увидит эту информацию.
Проблема
Проблема безопасности может возникнуть, когда злоумышленник крадет session_id
другого пользователя. Без какой-либо проверки он сможет выдать себя за этого пользователя. Нам нужно найти способ уникальной идентификации клиента (а не пользователя).
Одна стратегия (наиболее эффективная) включает проверку, совпадает ли IP-адрес клиента, начавшего сеанс, с IP-адресом лица, использующего сеанс.
if(logging_in()) {
$_SESSION['user'] = 'someuser';
$_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
}
// The Check on subsequent load
if($_SESSION['ip'] != $_SERVER['REMOTE_ADDR']) {
die('Session MAY have been hijacked');
}
Проблема этой стратегии заключается в том, что если клиент использует балансировщик нагрузки или (при длительной сессии) пользователь имеет динамический IP-адрес, он вызовет ложное предупреждение.
Другая стратегия включает проверку пользовательского агента клиента:
if(logging_in()) {
$_SESSION['user'] = 'someuser';
$_SESSION['agent'] = $_SERVER['HTTP_USER_AGENT'];
}
// The Check on subsequent load
if($_SESSION['agent'] != $_SERVER['HTTP_USER_AGENT']) {
die('Session MAY have been hijacked');
}
Недостатком этой стратегии является то, что если клиент обновляет свой браузер или устанавливает надстройку (некоторые добавляют к пользовательскому агенту), строка пользовательского агента изменится и вызовет ложное предупреждение.
Другая стратегия - вращать session_id
на каждые 5 запросов. Таким образом, теоретически session_id
не остается достаточно долго, чтобы его можно было похитить.
if(logging_in()) {
$_SESSION['user'] = 'someuser';
$_SESSION['count'] = 5;
}
// The Check on subsequent load
if(($_SESSION['count'] -= 1) == 0) {
session_regenerate_id();
$_SESSION['count'] = 5;
}
Вы можете комбинировать каждую из этих стратегий по своему желанию, но вы также комбинируете недостатки.
К сожалению, ни одно решение не является надежным. Если ваш session_id
скомпрометирован, вы в значительной степени готовы. Вышеуказанные стратегии являются всего лишь мерой отсрочки.