Фиксация / захват сеанса PHP

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

Однако я не уверен, что правильно понимаю вещи.

Чтобы помочь предотвратить фиксацию сеанса, достаточно вызвать session_regenerate_id (true); после успешного входа в систему? Кажется, я правильно это понимаю.

Он также говорит об использовании жетонов, передаваемых в URL-адресах через $ _GET, чтобы предотвратить захват сеанса. Как это будет сделано точно? Я предполагаю, что когда кто-то регистрируется в вас, вы создаете свой токен и храните его в переменной сеанса, а затем на каждой странице вы сравниваете эту переменную сеанса со значением переменной $ _GET?

Будет ли этот токен изменяться только один раз за сеанс или на каждую загрузку страницы?

Также является ли это хорошим способом предотвращения угона, без необходимости передавать значение в URL-адресах? это было бы намного проще.

Хорошо, есть две отдельные, но связанные проблемы, и каждый из них обрабатывается по-разному.

Фиксация сеанса

Здесь злоумышленник явно задает идентификатор сеанса для пользователя. Как правило, в 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 заключается только в том, что скомпрометирован идентификатор сеанса. При фиксации идентификатор устанавливается в значение, которое злоумышленник знает перед собой. В 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(); } 

Обе атаки сеанса имеют одинаковую цель: получить доступ к законному сеансу другого пользователя. Но векторы атаки различны:

  • В атаке фиксации сеанса злоумышленник уже имеет доступ к действительному сеансу и пытается заставить жертву использовать этот конкретный сеанс.

  • При атаке с захватом сеанса злоумышленник пытается получить идентификатор сеанса жертвы для использования своего сеанса.

В обеих атаках идентификатор сеанса – это конфиденциальные данные, на которые нацелена атака. Таким образом, идентификатор сеанса должен быть защищен как для доступа к чтению (Session Hijacking), так и для доступа на запись (Session Fixation).

В этом случае также применяется общее правило защиты конфиденциальных данных с использованием HTTPS. Кроме того, вы должны сделать следующее:

Чтобы предотвратить атаки с фиксацией сеанса , убедитесь, что:

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

Чтобы предотвратить атаки с захватом сеанса , убедитесь, что:

  • идентификатор сеанса в cookie доступен только на вашем сервере (установите session.cookie_httponly на true )
  • используется дополнительный источник энтропии (см. session.entropy_file ), поскольку генератор случайных чисел PHP имеет известную слабость ; многие рекомендации по безопасности предлагают не менее 128 бит длины энтропии (см. session.entropy_length )
  • используется сильная криптографическая хеш-функция (см. session.hash_function ); в лучшем случае это дорогостоящая хеш-функция, подобная Whirlpool , например, в пять раз медленнее, чем MD5, и, таким образом, допускает только пятую часть операций хэша в противоположность MD5.

Чтобы предотвратить обе атаки сеанса, убедитесь, что:

  • чтобы принимать только сеансы, инициированные вашим приложением. Вы можете сделать это, отпечатав сеанс при запуске с информацией о клиенте. Вы можете использовать идентификатор User-Agent, но не использовать удаленный IP-адрес или любую другую информацию, которая может измениться между запросами.
  • изменить идентификатор сеанса с помощью session_regenerate_id(true) после попытки аутентификации ( true только при успешном завершении) или сменить привилегии и уничтожить старый сеанс. (Обязательно сохраните любые изменения $_SESSION с помощью session_write_close до восстановления идентификатора, если вы хотите сохранить сеанс, связанный со старым идентификатором, иначе эти изменения будут затронуты только сеансом с новым идентификатором.)
  • для использования правильной реализации истечения срока действия сеанса (см. Как мне закончить сеанс PHP через 30 минут? ).

Знаки, которые вы упоминаете, – это номер «nonce», который используется один раз. Они не обязательно должны использоваться только один раз, но чем дольше они используются, тем выше вероятность того, что nonce можно будет захватить и использовать для захвата сеанса.

Другим недостатком nonces является то, что очень сложно создать систему, которая их использует, и позволяет несколько параллельных окон в одной и той же форме. например, пользователь открывает два окна на форуме и начинает работать над двумя сообщениями:

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

Если у вас нет способа отслеживать несколько окон, вы сохраните только одно – это окна B / Q. Когда пользователь затем отправляет свое сообщение из окна A и переходит в nonce 'P', система будет отклонять сообщение как P != Q

Я не читал статью Шифлетта, но, думаю, вы что-то неправильно поняли.

По умолчанию PHP передает токен сеанса в URL-адрес всякий раз, когда клиент не принимает файлы cookie. В самом общем случае токен сеанса хранится как файл cookie.

Это означает, что если вы поместите токен сеанса в URL-адрес PHP, он узнает его и попытается использовать его впоследствии. Фиксация сеанса происходит, когда кто-то создает сеанс, а затем обманывает другого пользователя для совместного использования одного и того же сеанса, открывая URL-адрес, который содержит токен сеанса. Если пользователь каким-то образом аутентифицируется, тогда злоумышленник знает маркер сеанса аутентифицированного пользователя, у которого могут быть разные привилегии.

Как я понимаю, Шифлетт объясняет, что обычно нужно регенерировать другой токен каждый раз при изменении прав пользователя.

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