Фиксация сессий PHP / угон

145

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

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

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

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

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

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

те2
источник
Может быть, вы могли бы добавить ссылки на страницы, где вы нашли эти рекомендации.
Гамбо

Ответы:

220

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

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

Здесь злоумышленник явно устанавливает идентификатор сеанса для пользователя. Обычно в 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 Hijacking

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

Вы не можете напрямую предотвратить угон сеанса. Однако вы можете сделать шаги, чтобы сделать его очень сложным и сложным в использовании.

  • Используйте сильный идентификатор хеша сеанса: session.hash_functionin 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 на стороне браузера, чтобы сделать то же самое (используя локальное хранилище). Затем, когда вы отправляете запрос, просто возьмите одноразовый номер токена и убедитесь, что на сервере совпадает одноразовый номер. Сделав это, вы сможете обнаружить захваченный сеанс, поскольку у злоумышленника не будет точного счетчика, или, если он это сделает, у вас будет 2 системы, передающие одинаковое количество, и они могут сказать, что одна из них подделана. Это не будет работать для всех приложений, но это один из способов борьбы с проблемой.

Записка о двух

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

Сессия ID Регенерация

Всякий раз, когда вы восстанавливаете идентификатор сеанса, используя session_regenerate_idстарый сеанс, его следует удалить. Это происходит прозрачно с основным обработчиком сеанса. Однако некоторые пользовательские обработчики сессийsession_set_save_handler() не делают этого и открыты для атаки на старые идентификаторы сессий. Убедитесь, что, если вы используете пользовательский обработчик сеанса, что вы отслеживаете открываемый идентификатор, и если он не тот, который вы сохраняете, вы явно удаляете (или меняете) идентификатор старого.

Используя обработчик сеанса по умолчанию, вам достаточно просто позвонить session_regenerate_id(true). Это удалит старую информацию о сеансе для вас. Старый идентификатор больше не действителен и приведет к созданию нового сеанса, если злоумышленник (или кто-либо еще в этом отношении) попытается использовать его. Будьте осторожны с пользовательскими обработчиками сессий, хотя ....

Уничтожение сессии

Если вы собираетесь уничтожить сеанс (например, при выходе из системы), убедитесь, что вы уничтожили его полностью. Это включает в себя удаление куки. Использование session_destroy:

function destroySession() {
    $params = session_get_cookie_params();
    setcookie(session_name(), '', time() - 42000,
        $params["path"], $params["domain"],
        $params["secure"], $params["httponly"]
    );
    session_destroy();
}
ircmaxell
источник
4
Использование 5 вместо 4 битов на символ никоим образом не меняет «силу» (что в данном случае означает «сила»). Но хотя ваши пункты в целом целесообразны, в них отсутствуют некоторые важные детали. Например, что происходит с сеансом, связанным со старым идентификатором сеанса, или как следует обрабатывать сеанс со старым идентификатором сеанса после того, как он стал недействительным.
Гамбо
2
@battal: Нет, в этом все дело. session_regenerate_idне делает недействительным сеанс, который все еще связан со старым идентификатором; только если для параметра delete_old_session задано значение true, сеанс будет уничтожен. Но что, если злоумышленник инициирует регенерацию идентификатора?
Гамбо
6
Я не согласен с восстановлением сеанса каждый раз, когда вы меняете переменную сеанса, это следует делать только при входе / выходе из системы. Также проверка пользовательского агента не имеет смысла, а проверка REMOTE_ADDR проблематична. Я хотел бы добавить одну вещь:session.entropy_file = /dev/urandom . Доказано, что внутренняя генерация энтропии в PHP чрезвычайно слабая, а пул энтропии, предоставляемый / dev / random или / dev / uranom, - лучшее, что вы можете получить на веб-сервере без аппаратного обеспечения.
Ладья
4
Также вы должны добавить session.cookie_httponly и session.cookie_secure. Первый помогает помешать XSS (но это не идеально). Второй - лучший способ остановить OWASP A9 ...
ладья
4
Не понимаю такого замечательного ответа, но упускаю самую важную часть: используйте SSL / HTTPS. Приращение счетчика является источником проблем с несколькими запросами, которые выполняются быстро друг за другом, пользователь дважды обновляет страницу или дважды нажимает кнопки отправки. Решение по IP-адресу в настоящее время является проблемой для всех мобильных пользователей и постоянно меняющихся IP-адресов. Вы могли бы взглянуть на первый набор IP, но все же он вызывает проблемы. Лучше всего предотвратить обнаружение идентификатора сеанса с самого начала, который использует SSL / HTTPS.
Санне
37

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

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

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

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

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

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

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

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

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

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

Токены, которые вы упоминаете, являются "nonce" - число, используемое один раз. Их не обязательно использовать только один раз, но чем дольше они используются, тем выше вероятность того, что одноразовый номер может быть захвачен и использован для захвата сеанса.

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

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

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

Марк Б
источник
Так какое это имеет отношение к фиксации сессии?
ладья
2
У него есть веская точка зрения, особенно в области одновременного использования множества запросов AJAX.
DanielG
2

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

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

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

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

Andrea
источник
Чтобы добавить к этому, убедитесь, что уничтожили все ранее открытые сеансы, так как они все еще будут действительны с существующими разрешениями пользователя.
корродированный
0

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

ладья
источник