Насколько безопасны переменные сессии в PHP?
У меня есть скрипт для авторизации, который проверяет имя пользователя и пароль на основе данных в таблице 'user'. Кроме того, у меня есть таблица 'roles', которая определяет уровень доступа каждого пользователя. Предполагая, что я использую безопасные скрипты для входа, есть ли какие-либо уязвимости в том, чтобы выполнять дополнительный запрос (после успешной авторизации) к таблице 'roles', чтобы выяснить уровень авторизации пользователя и сохранять это значение в сессионной переменной? Идея заключается в том, что на любой странице с разными уровнями доступа я мог бы просто запрашивать сессионную переменную, чтобы узнать уровень авторизации вошедшего пользователя.
Спасибо.
4 ответ(ов)
Сессии значительно безопаснее, чем, например, куки. Тем не менее, существует возможность украсть сессию, что даст злоумышленнику полный доступ к тому, что находится в этой сессии. Существуют некоторые способы минимизировать этот риск, такие как проверка IP-адреса (которая неплохо работает, но является довольно примитивным методом и, следовательно, не надежна самостоятельно) и использование nonce. Как правило, с nonce вы можете создать "токен" для каждой страницы, чтобы каждая страница проверяла соответствие nonce предыдущей страницы с тем, что у нее хранится.
Однако любой из методов проверки безопасности приводит к потере удобства для пользователя. Если вы используете проверку IP-адреса и пользователь находится за межсетевым экраном (или в любой другой ситуации, когда IP-адрес меняется), ему придется повторно аутентифицироваться каждый раз при потере IP. А с nonce вы можете столкнуться с такой, всегда веселой, ситуацией, как «Назад приведет к ошибке на этой странице».
С куки же хакер может украсть сессию, используя достаточно простые техники XSS. Если вы храните идентификатор сессии пользователя в куке, они также уязвимы к этому. Таким образом, хотя сессия и доступна только тому, кто может осуществить хак на уровне сервера (что требует гораздо более сложных методов и, как правило, определенного уровня привилегий, если ваш сервер надежен), вам все равно потребуется дополнительный уровень проверки при каждом запросе скрипта. Не стоит использовать куки и AJAX вместе, так как это упрощает задачу хакерам в случае кражи куки; ваши AJAX-запросы могут не получать проверки безопасности при каждом запросе. Например, если страница использует nonce, но страница никогда не перезагружается, скрипт может только проверять это соответствие. И если кука содержит метод аутентификации, я теперь с легкостью могу заниматься своими злодеяниями, используя украденную куку и уязвимость AJAX.
Только скрипты, выполняющиеся на вашем сервере, имеют доступ к массиву _SESSION. Если вы определите область действия сессии (session cookie), вы даже сможете ограничить её доступ к конкретной директории. Единственный способ, как кто-то другой мог бы получить данные сессии — это вставить PHP-код в одну из ваших страниц.
Что касается используемой вами системы, это допустимо и является хорошим способом уменьшить количество обращений к базе данных, но имейте в виду, что это потребует от пользователя выхода из системы и последующего входа, чтобы изменения в авторизации вступили в силу. Таким образом, если вы захотите заблокировать учетную запись, и этот пользователь уже вошёл в систему, вы не сможете это сделать.
Стоит отметить, что в Apache суперглобальный массив PHP $_SESSION
доступен для разных виртуальных хостов. Рассмотрим следующий сценарий:
- Ваш сервер хостит два домена: example.com и instance.org. PHP-сессии хранятся в куках, которые ограничены текущим доменом.
- Пользователь заходит на example.com и получает идентификатор сессии. Этот сайт устанавливает некоторые переменные сессии (которые хранятся на сервере, а не в куке).
- Третья сторона перехватывает куку во время передачи и передает ее на instance.org. В результате instance.org теперь имеет доступ к переменным сессии example.com.
Это не является большой проблемой, когда вы контролируете все виртуальные хосты на своем сервере, но если вы находитесь на общем сервере, это может вызвать серьезные проблемы.
Если вы полагаетесь на значение, хранящееся в сессионной переменной для определения ролей, вы теряете возможность изменять значение в базе данных и видеть эти изменения в текущей сессии пользователя. В Zend Framework четко проводится различие между аутентификацией и авторизацией, и в руководстве содержатся настоятельные предупреждения о том, что в сессии следует хранить минимально необходимое количество данных (например, "Да, это пользователь №37, и он вошел в систему").
Что касается 'безопасности', то если вы не находитесь на общем хостинге, поводов для беспокойства нет. На правильно настроенном общем хостинге также должно быть относительно безопасно.
Как предотвратить SQL-инъекции в PHP?
Как санировать пользовательский ввод с помощью PHP?
Достаточны ли подготовленные выражения PDO для предотвращения SQL-инъекций?
SQL-инъекция, обхватывающая mysql_real_escape_string()
Функции startsWith() и endsWith() в PHP