Фиксация сессий 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, убедитесь, что:
- идентификатор сессии в файле 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" - число, используемое однажды Их не обязательно использовать только один раз, но чем дольше они используются, тем выше вероятность того, что одноразовый номер может быть захвачен и использован для захвата сеанса.
Еще одним недостатком одноразовых номеров является то, что очень трудно создать систему, которая использует их и допускает несколько параллельных окон в одной форме. Например, пользователь открывает два окна на форуме и начинает работать над двумя сообщениями:
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.