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

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

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

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

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

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

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

Ответ 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();
}

Ответ 2

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

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

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

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

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

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

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

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

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

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

Ответ 3

Знаки, о которых вы упоминаете, являются "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.

Ответ 4

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

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

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

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

Ответ 5

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