Русское сообщество fluxbb

Быстрый лёгкий надёжный форумный движок

Вы не вошли.

Объявление

Вы можете внести свой вклад в содержание сайта. Жертвователи попадут в почетную группу "Спонсоры". Поддержать сайт.

#1 2011-05-22 09:31:15

artoodetoo
Admin by chance
Зарегистрирован: 2008-09-09
Сообщений: 881
Сайт

Обработка сессий. Привязка к аутентификации пользователя.

Коротко о том как работают сессии в PHP

Переменные в скриптах PHP живут до завершения этого скрипта, т.е. в пределах одного http-запроса (одной странички, если так понятнее). Если есть нужда сохранить данные для следующего запроса (другой странички), можно сохранить их в переменной $_SESSION . Магическим образом в следующий раз они будут там. Но не навечно. Если закрыть окно браузера и снова отрыть, это будет считаться другая сессия и данные там будут другие.

Сессии зависят от куков. При создании сессии PHP ищет куку со специальным именем "PHPSESSID" (это имя можно переопределить, но об этом позже). Если такой куки нет, она создается и в нее записывается случайное значение (мы можем переопределить и эту "случайность"). Время жизни этой куки устанавливается в 0, значит она будет забыта как только мы закроем окно браузера.
Если мы зашли на сайт с нескольких браузеров, например в IE и FF, у каждого из них будет своя кука, это будут две разные сессии. Но внутри одного браузера в разных вкладках кука и сессия одна и та же. 

Для работы с сессиями в PHP есть семейство функций с именами session_*. Как минимум где-то в начале скрипта надо вызвать session_start(), только тогда переменная $_SESSION будет доступна.

Новичка может сбить с толку имя функции. session_start как правило не стартует сессию! Она пытается продолжить уже открытую сессию, и только если это невозможно, стартует новую.

Важно помнить, что первый (или единственный) вызов session_start должен произойти до любого echo, т.к. сессия работает с кукой, кука передаётся в заголовке, заголовки формируются до тела страницы!

Так вот, при вызове session_start считывается кука с именем PHPSESSID и значение этой куки служит ключем для доступа к файлу на сервере. Если все прошло без ошибок, содержимое этого файла присваивается переменной $_SESSION. Эта "сеперглобальная" переменная доступна из всех функций и методов без необходимости описания global. По окончании работы скрипта, содержимое этой переменной сохраняется в тот же файл для следующих запросов.


There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.

Offline

#2 2011-05-22 09:35:33

artoodetoo
Admin by chance
Зарегистрирован: 2008-09-09
Сообщений: 881
Сайт

Re: Обработка сессий. Привязка к аутентификации пользователя.

На всякий случай приведу определение из документации к Yii framework:

Аутентификация и авторизация необходимы на страницах, доступных лишь некоторым пользователям.
Аутентификация — проверка, является ли некто тем, за кого себя выдаёт. Обычно она подразумевает ввод логина и паролях [ ... ]
Авторизация — проверка, может ли аутентифицированный пользователь выполнять определённые действия

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

Мне показалось, что будет логичным связать аутентификацию пользователя и его сессию

Очень уж близкие понятия. Пользователь узнается тоже по содержимому куки. Если пользователь сделал logout, это уже не тот пользователь и сессия у него должна закончиться. А что если указать PHP, такое
сессионная кука == аутентификационная кука?
Это можно сделать через вызов session_name(). Я прописал в common.php:

session_name($cookie_name);
session_start();

Возникает ошибка. Причина в формате данных аутентификационной куки. Дело в том, что сессионная переменная $_SESSION между запросами сохраняется во временном файле. Имя этого файла зависит от значения в куке, требуется чтобы там были только допустимые символы.
Я воспользовался панелью Web Developer для Firefox и заглянул в куку:

pun_cookie_4835b6 = 3|8a44b39505a0b81400a7b76692f12ea8d9f3df4b|1306048730|d4fd966d00fd8b3141de8cdfd30e2628fa7a12ee

Значение куки - 4 фрагмента, разделённые "|", это так называемый HMAC:

user_id | password_hash | expiration_time | cookie_hash

Ok. Я определил свои обработчики записи и чтения сессионных данных через вызов session_set_save_handler(). На входе у меня id из аутентификационной куки, а я трансформирую его в допустимый набор символов.

$id = md5($id);

Ошибка ушла. На сервере во временной папке создаются файлы с сессионными данными, но ерунда все-таки вышла. Оказалось, что на каждую страницу создается новая сессия. Почему?
Стойкость алгоритма HMAC состоит в том, что кроме самих данных там присутствует expiration_time и контрольная сумма всей куки. Движок форума обновляет expiration_time  всякий раз после аутентификации. Соответственно мой md5($id) тоже всякий раз новый.
То есть я должен исключить из ид_сессии время и контрольную сумму

$array = explode('|' , $id);
$id = md5($array[0] . $array[1]);

т.е. ключем сессии будет не вся кука, а её фрагмент:
user_id | password_hash | expiration_time | cookie_hash

Вот теперь сессия стала действительно сессией, зависящей от аутентификации!


There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.

Offline

#3 2011-05-24 08:47:16

artoodetoo
Admin by chance
Зарегистрирован: 2008-09-09
Сообщений: 881
Сайт

Re: Обработка сессий. Привязка к аутентификации пользователя.

О времени жизни аутентификационной куки FluxBB. Какая кука у гостя.

Поведение изучено мной при написании своего класса аутентификации по флаксовской куке.
Первый раз кука выставляется в скрипте /login.php, вся дальнейшая работа происходит в функции check_cookie() в модуле include/functions.php.

  1. Если "Гость" не пытается "войти", кука не выставляется вообще.

  2. Если в диалоге "Войти" пользователь поставил галочку в пункте "Узнавать меня автоматически", то время жизни куки выставляется в 14 дней.

  3. Если пользователь не включал галочку, время жизни куки устанавливается в значение o_timeout_visit, которое по умолчанию равно 30 минут, т.е. она НЕ пропадет сразу, как только пользователь закроет браузер. Но если он не заходил полчаса, то кука станет недействительна.

  4. Если аутентификационная кука есть, по форме данных похожа на HMAC, но проверка провалилась: либо хеш пароля не совпал, либо контрольная сумма куки не совпала. Форум выставляет новую куку где указан пользователь "Гость", хеш пароля случайный, а время жизни куки 1 год.

  5. То же самое происходит когда пользователь кликнул "Выйти" - выставляется такая же кука, как в предыдущем случае

Интересный фрагмент кода про продление куки:

        // Send a new, updated cookie with a new expiration timestamp
        $expire = ($cookie['expiration_time'] > $now + $pun_config['o_timeout_visit']) ? $now + 1209600 : $now + $pun_config['o_timeout_visit'];
        pun_setcookie($pun_user['id'], $pun_user['password'], $expire);

Выше этого фрагмента стоит проверка на $cookie['expiration_time'] > $now, то есть получается, что

  • Если кука будет жить еще долго, более чем 30 минут (пользователь ставил галочку), то мы продляем её жизнь на 2 недели.

  • Если кука еще не просрочена, но устареет в ближайшие 30 минут, то форум дает 30 минут от текущего времени.

Вернемся к нашим баранам. Аутентификационная кука == сессионная кука.

Как зависит наша самодельная сессия от авторизации.

  • Если пользователь не авторизован и кука отсутствует, session_start() создаст новую куку с именем как у аутентификационной куки и со случайным значением. Она не будет соответствовать формату hmac, значит форум такую куку не примет и Гость останется Гостем. Время жизни такой куки будет 0 - до закрытия браузера или до "входа" пользователя.

  • Если пользователь авторизован успешно, login.php создаст куку, а продлевать будет include/functions.php. Сессия просто будет выдергивать из нее id и password_hash - неизменяемые части. Время жизни будет постоянно увеличиваться.

  • Если пользователь вышел, создается "вечная" кука с id==1 и password_hash случайной строкой. Это уже новая сессия, значит сессионные старые переменные будут недействительны.

При этом время жизни файла с сессионными данными зависит совсем от других факторов. Настройка session.gc_maxlifetime=1440 это значит, файл будет жить как минимум 24 минуты с момента последнего изменения.

Совпадение сессий

Будут ли совпадать сессии у залогиненного пользователя, вошедшего с разных браузеров/компьютеров? Да. У них сессионная часть куки совпадает.

Будут ли совпадать сессии у разных Гостей? Нет. У них сессионная часть куки разная.


Кажется нет препятствий к использованию моей задумки. Немного потестирую и выложу код.


There are two hard things in computer science: cache invalidation, naming things, and off-by-one errors.

Offline

Подвал доски

Под управлением FluxBB. Хостинг Hostens