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

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

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

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

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

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

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

5 ответов

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

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

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

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

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

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

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

Общее правило защиты конфиденциальных данных с использованием 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 минут?).

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

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

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.

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

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

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

Другие вопросы по тегам