×
Закрытие
×

Дополнительные материалы бесплатно предоставляются только зарегистрированным пользователям.

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

Для тех кто не зарегистрирован, можно это сделать на вкладке Регистрация.

  • Создаем сайт для работы в Интернете

    1. Причины создания пошаговой инструкции по разработке самописного сайта
    2. Тема создаваемого сайта
    3. В чем будет заключаться монетизация
    4. Функционал
    5. Этапы создания
    6. Текущее состояние создаваемого сайта

    Здравствуйте уважаемый посетитель!

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

    Причем чтобы такой сайт был создан не в стандартном исполнении на основе какой-нибудь бесплатной СMS, а заточенный под себя, с возможностью обеспечить ему должную безопасность и реализовать все свои индивидуальные потребности.

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

    При этом в материалах сборника приводится не только подробное описание каждого этапа создаваемого самописного сайта, но и бесплатно предоставляются все исходные коды с соответствующими таблицами базы данных. Что существенно упрощает использования предоставляемого шаблона сайта под свои конкретные задачи.

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

    И надеюсь, что данный материал позволит многим желающим не только создать свой сайт для работы в сети Интернет, но и поможет овладеть необходимой компетенцией для занятия профессиональным веб-программированием.

Самописный сайт своими руками!

Текущее состояние создаваемого сайта

Здесь можно посмотреть текущее состояние самописного сайта, который создается для работы в Интернете в рамках цикла статей Как сделать сайт.

Где в дополнительных материалах можно бесплатно скачать исходные файлы сайта с таблицами MySQL.

Вы здесь: Главная → Сборник статей → Авторизация  → Удаляем истекшие сессии с заданной периодичностью


Автор: / Дата:

Удаляем истекшие сессии с заданной периодичностью

Здравствуйте уважаемый посетитель!

Сегодня коснемся еще одного вопроса, в какой-то мере, относящегося к безопасности системы авторизации. А именно: посмотрим, как можно с помощью пользовательского скрипта упорядочить удаление сессий с истекшим сроком жизни.

Рассмотрение это обусловлено тем, что по умолчанию существующий PHP-механизм управления сессиями основан на вероятности удаления (сборкой мусора) из хранилища истекших сессий. И при определенных условиях это может происходить через достаточно большие промежутки времени. А значит, время нахождения в хранилище соответствующих файлов может быть чрезмерно большим. И очевидно, при таких условиях стоит учитывать определенную вероятность их несанкционированного использования.

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

Однако, для более полного раскрытия темы работы с PHP-сессиями, думаю, стоит рассмотреть и этот, нестандартный способ, который при определенных условиях может быть весьма полезен.

Содержание


  • Недостатки существующего механизма сборки мусора
  • Принцип действия пользовательского скрипта удаления истекших сессий
  • Практическая реализация очищения хранилища с заданной периодичностью.
  • Проверка работы созданного скрипта.
  • Исходные файлы сайта

Недостатки существующего механизма сборки мусора


Ранее, при создании системы авторизации уже рассказывалось об особенностях работы существующего, встроенного в PHP, механизма удаления истекших сессий. И приводились свойственные ему недостатки, а именно:

  • На низко загруженном сайте сессии после истечения времени жизни могут удаляться достаточно долго. И как следствие, их сессионные файлы в течение длительного времени могут быть объектом взлома при совершении хакерских атак.
  • На высоко загруженных сайтах сборка мусора может выполняться слишком часто. А так как это происходит во время обработки запроса, то частое выполнение такой операции может вызывать у пользователей дополнительную задержку загрузки страниц.

Следует отметить, что в существующем механизме запуск сборщика мусора происходит с определенной вероятностью, которая задается специальным параметром "session.gc_divisor". По умолчанию его значение равно 1000 (о том, как посмотреть текущие значения параметров сессий, рассказывалось в одном из разделов вводной статьи об авторизации пользователей).

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

Для высоко нагруженных сайтов это может происходить с приемлемой периодичностью. Хотя здесь тоже следует учесть неравномерность посещений в зависимости от времени суток и дней недели.

А если говорить о сайтах с небольшой посещаемостью, то запуск сборщика можно ждать очень долго. Например, при такой настройке параметра "session.gc_divisor", при посещаемости сайта в 100 пользователей в сутки, время нахождения истекших сессий в хранилище будет исчисляться днями. Что конечно, неприемлемо для нормальной работы системы авторизации.

Можно, конечно, уменьшить значение параметра "session.gc_divisor". Но все равно с таким алгоритмом работы данный механизм не сможет гарантировано обеспечить своевременное очищение хранилища.

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

Принцип действия пользовательского скрипта удаления истекших сессий


Работа данного скрипта будет основана на использовании функции session_gc(), предназначенной для сборки мусора (garbage collection) сессий с истекшим сроком жизни.

Как отмечалось ранее, в существующем механизме, PHP по умолчанию выполняет сборку мусора, основанную на вероятности. Наша задача состоит в том, чтобы заставить функцию session_gc() выполнять свою работу в определенное время с заданной периодичностью.

Для этого достаточно будет реализовать следующий, довольно несложный, алгоритм работы скрипта:

  • При первом выполнении скрипта в папке, предназначенной для размещения файлов сессий, должен быть создан специальный (тестовый) файл, который в дальнейшем будет использоваться для контроля времени последнего вызова функции сборки мусора.
  • При выполнении каждого запроса скрипт проверяет время последней модификации тестового файла. И если это время превысило установленный порог, то должен произойти вызов функции session_gc(), и соответственно, очищение хранилища. А также должно быть установлено новое время модификации тестового файла.
  • В случае же, когда время последнего вызова функции сборки мусора не достигнет заданного значения, то работа системы авторизации должна происходить обычным образом без выполнения каких-либо действий функции session_gc().

В связи с тем, что для инициализации доступа к хранилищу необходима активная сессия, следует предусмотреть работу скрипта, как при ее наличии, так и при обработке запросов без нее.

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

Практическая реализация очищения хранилища с заданной периодичностью.


После того как мы определили алгоритм работы скрипта, теперь перейдем к его реализации. Причем сделаем это в виде пользовательской функции, которую разместим, как обычно мы делали для остальных PHP-функций, в папке "php" корневого каталога сайта.

Ниже показан PHP-код такой функции, имеющей два параметра в виде переменных: $gc_period - значение, определяющее периодичность запуска функции сборки мусора и $gc_test_file - путь к каталогу, предназначенному для хранения файлов сессий.

  1. <?php

  2. //----Функция удаления истекших сессий-----

  3. function sessionGs ($gc_period, $gc_test_file) {

  4. if (file_exists($gc_test_file)) { //Если тестовый файл существует

  5. if (time() - filemtime($gc_test_file) > $gc_period) { //Если время последней модификации тестового файла превысило заданную величину

  6. if (session_id()) { //Если сессия уже была запущена

  7. setcookie(session_name(), session_id(), time()-60*60*24, '/'); //Удаляем сессионную cookie

  8. if (isset($_COOKIE['key1'])) setcookie("key1", "", time()-60*60*24, "/", $_SERVER['SERVER_NAME'], 0, 1); //При наличии cookie с одноразовым ключем, удаляем ее

  9. session_gc(); //Вызываем функцию сборки мусора

  10. session_destroy(); //Уничтожаем сессию

  11. }

  12. else { //Если нет активной сессии

  13. session_start(); //Стартуем сессию

  14. setcookie(session_name(), session_id(), time()-60*60*24, '/'); //Удаляем сессионную cookie

  15. session_gc(); //Вызываем функцию сборки мусора

  16. session_destroy(); //Уничтожаем сессию

  17. }

  18. touch($gc_test_file); //Обновляем время последней модификации тестового сайта

  19. return true; //Возвращаем истину

  20. }

  21. else { //Если время последней модификации тестового файла не превысило заданную величину

  22. return false; //Возвращаем ложь

  23. }

  24. }

  25. else { //Если тестового файла не существует

  26. touch($gc_test_file); //Создаем тестовый файл

  27. return false; //Возвращаем ложь

  28. }

  29. }

  30. ?>

Рис.1 Функция удаления истекших сессий с заданной периодичностью

В данном коде каждое действие сопровождается комментариями, и очевидно, нет необходимости делать еще какие-то дополнительных пояснений.

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

Если да, то выполняется удаление сессионной cookie (поз.7) вместе с cookie, в которой размещен одноразовый ключ (поз.8). После чего происходит вызов функции сборки мусора session_gc() (поз.9) и уничтожение сессии (поз.10).

Если же функция вызвана без наличия активной сессии, то для инициализации доступа к хранилищу, сначала запускается новый сценарий (поз.13). А затем выполняются все аналогичные операции по удалению cookie, сборки мусора и уничтожению сессии.

После того, как мы создали нужную функцию, теперь осталось только прописать ее вызов с заданными параметрами. Сделаем мы это в файле "check_auth.php", в котором при обработке запроса происходит проверка подлинности пользователя.

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

Ниже показан существующий на данный момент код файла "check_auth.php" с добавленными из этих соображений двумя строками вызова пользовательской функции (выделено светлым цветом).

  1. <?php

  2. $session_check = 0; //Устанавливаем разрешающий флаг авторизации

  3. if (isset($_COOKIE['alert'])) { //При наличии cookie 'alert' с сообщением об ошибке

  4. $GLOBALS['alert'] = $_COOKIE['alert']; //Для вывода в диалоговое окно браузера записываем в глобальную переменную $GLOBALS['alert'] ообщения об ошибке

  5. setcookie ("alert", "", time()-60*60*24, "/", $_SERVER['SERVER_NAME']); //Удаляем cookie 'alert'

  6. }

  7. else {

  8. if (!empty($_COOKIE[ini_get('session.name')])) { //Если существует активная сессия

  9. session_start(); //Возобновляем сессию

  10. if (!sessionGs(900, 'tmp/session_last_time.txt')) { //Если при вызове пользовательской функции удаления истекших сессий получаем ложь (время последней модификации тестового файла не превысило заданную величину)

  11. if (isset($_SESSION['key1'])) $session_key1 = $_SESSION['key1']; //Если переменная "key1" в сессии существует, то PHP-переменной $session_key1 присваивается ее значение

  12. else //Если нет

  13. $session_key1 = ""; //Переменной $session_key1 присваивается пустое значение;

  14. if (isset($_COOKIE['key1'])) $cookie_key1 = $_COOKIE['key1']; //Если cookie "key1" существует, то PHP-переменной $cookie_key1 присваивается ее значение

  15. else //Если нет

  16. $cookie_key1 = ""; //Переменной $cookie_key1 присваивается пустое значение

  17. if ($session_key1 != "" && $cookie_key1 != "" && $session_key1 == $cookie_key1) { //Если одноразовый ключ сессии и cookie совпадают (подтверждение подлинности пользователя)

  18. $key1_hash = hash('sha256', microtime()); //Формируем одноразовый хеш-ключ

  19. setcookie ("key1", $key1_hash, 0, "/", $_SERVER['SERVER_NAME'], 0, 1); //Отправляем на сторону клиента cookie со вновь созданным одноразовым ключем

  20. $_SESSION["key1"] = $key1_hash; //Записываем данные ключа в переменную сессии с именем "key1"

  21. if (isset($_SESSION['agent'])) { //Проверяем, определена ли переменная сессии, содержащая данные HTTP-заголовка User-Agent

  22. $agent = $_SERVER['HTTP_USER_AGENT']; //Получаем данные об агенте из запроса

  23. if ($_SESSION['agent'] == $agent) { //Если данные об агенте совпадают с данными сессии

  24. $session_check = 1; //Устанавливаем разрешающий флаг авторизации

  25. }

  26. else { //Если данные об агенте не совпадают с данными сессии

  27. $error_auth = 'Подпись пользователя не подтверждена. В целях безопасности текущая сессия закрыта!\nДля получения прав доступа необходимо вновь авторизоваться через соответствующую форму.'; //Сообщение об ошибке

  28. sessionDelete($error_auth); //Вызываем функцию уничтожения сессии

  29. }

  30. }

  31. else { //Если переменная сессии, содержащая данные HTTP-заголовка User-Agent не определена

  32. $error_auth = 'Отсутствует подпись пользователя. В целях безопасности текущая сессия закрыта!\nДля получения прав доступа необходимо вновь авторизоваться через соответствующую форму.'; //Сообщение об ошибке

  33. sessionDelete($error_auth); //Вызываем функцию уничтожения сессии

  34. }

  35. $session_time = 900; //Устанавливаем порог отсутствия активности сессии

  36. if (isset($_SESSION['lasttime'])) { //Проверяем, определена ли переменная сессии с меткой времени

  37. if (time() - $_SESSION['lasttime'] < $session_time) { //Если время не активности сессии не превысило установленный порог

  38. $_SESSION['lasttime'] = time(); //Устанавливаем новую метку времени в переменную сессии

  39. }

  40. else { //Если время не активности сессии превысило установленный таймаут

  41. $session_check = 0; //Устанавливаем запрещающий флаг авторизации

  42. $error_auth = 'Время жизни сессии истекло. В целях безопасности текущая сессия закрыта!\nДля получения прав доступа необходимо вновь авторизоваться через соответствующую форму.'; //Сообщение об ошибке

  43. sessionDelete($error_auth); //Вызываем функцию уничтожения сессии

  44. }

  45. }

  46. if (isset($_SESSION['addr'])) { //Проверяем, определена ли переменная сессии с данными IP-адреса пользователя

  47. $addr = $_SERVER['REMOTE_ADDR']; //Получаем данные IP-адреса пользователя

  48. //$addr = '192.54.12.23'; //Вариант с фиксированным значением IP-адреса

  49. $reg_addr = preg_replace("/[^0-9]/", "", $addr); //Преобразуем адрес по регулярному выражению

  50. $addr_hash = hash('sha256', $reg_addr); //Формируем хеш адреса

  51. if ($_SESSION['addr'] != $addr_hash) { //Если данные хеша IP-адреса не совпадают с данными сессии

  52. $session_check = 0; //Устанавливаем запрещающий флаг авторизации

  53. $error_auth = 'Попытка несанкционированного входа в систему. В целях безопасности текущая сессия закрыта!\nДля получения прав доступа необходимо вновь авторизоваться через соответствующую форму.'; //Сообщение об ошибке

  54. sessionDelete($error_auth); //Вызываем функцию уничтожения сессии

  55. }

  56. }

  57. }

  58. else { //Если одноразовый ключ сессии и cookie не совпадают

  59. $error_auth = 'Достоверность пользователя не подтверждена. В целях безопасности текущая сессия закрыта!\nДля получения прав доступа необходимо вновь авторизоваться через соответствующую форму.'; //Сообщение об ошибке

  60. sessionDelete($error_auth); //Вызываем функцию уничтожения сессии

  61. }

  62. }

  63. else { //Если время последней модификации тестового файла превысило заданную величину

  64. $session_check = 0; //Устанавливаем запрещающий флаг авторизации

  65. $alert = 'Время жизни сессии истекло. В целях безопасности текущая сессия закрыта!\nДля получения прав доступа необходимо вновь авторизоваться через соответствующую форму.'; //Сообщение об ошибке

  66. }

  67. }

  68. else { //Если отсутствует активная сессия

  69. sessionGs(900, 'tmp/session_last_time.txt'); //Вызываем пользовательскую функцию удаления истекших сессий

  70. }

  71. }

  72. ?>

Рис.2 Добавление в файл check_auth.php вызова пользовательской функции удаления истекших сессий

Как видно, здесь пользовательская функция sessionGs() вызывается два раза. В строке 10, после возобновления сессии и в строке 69 при ее отсутствии.

Что касается параметров вызываемой функции, то первый, определяющий периодичность сборки мусора, установлен в значение 900 секунд. Что соответствует времени жизни сессии.

А вот для второго параметра, передающего функции путь к папке с файлами сессий, требуется пояснение.

Дело в том, что по умолчанию настройкой конфигурации PHP "session.save_path" задан путь к хранилищу сессий на сервера в соответствии с его файловой системой. И для каждого случая, место расположения этого каталога может быть различно (ранее уже упоминалось, как можно узнать текущие параметры конфигурации PHP).

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

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

Поэтому в данном случае используется путь не к хранилищу сервера, а к папке "tmp" вновь созданного корневого каталога сайта. В итоге, в качестве аргумента второго параметра пользовательской функции задан следующий путь: "tmp/session_last_time.txt", где "session_last_time.txt" - имя тестового файла.

А для того, чтобы переопределить для сайта данную установку воспользуемся соответствующей директивой файла ".htaccess". Ниже показаны настройки параметров сессий файла ".htaccess" с добавленной директивой "session.save_path" (выделено светлым фоном).

  1. # Настройки параметров сессий

  2. php_value session.name SESSID

  3. php_flag session.cookie_httponly 1

  4. php_value session.gc_maxlifetime 900

  5. php_value session.cookie_lifetime 0

  6. php_value session.save_path tmp/

  7. php_flag session.gc_probability 0

Рис.3 Переопределение пути к каталогу сессий в файле .htaccess

Можно обратить внимание, что в этой таблице отсутствует ранее установленная директива "session.gc_divisor", которая изменяла значение вероятности запуска сборщика мусора. А вместо нее добавлена другая директива session.gc_probability со значением 0, которая отключает сборку мусора на основе вероятности. Обусловлено это тем, что с применением данного скрипта теперь не требуется использование встроенного механизма удаления сессий.

Таким образом мы рассмотрели вариант, когда с помощью файла ".htaccess" можно изменить папку, предназначенную для хранения сессий. Однако, это не всегда удается. Бывает, что хостеры запрещают менять путь к этой папке. Как же тогда поступать?

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

Например, для тестового файла session_last_time.txt, вместо используемого здесь 'tmp/session_last_time.txt', может быть указан адрес: /home/wm586934/phptmp/session_last_time.txt. Где /home/wm586934/phptmp/ - реальный путь к папке хранилища сессий на сервере хостинга, на котором размещен тестовый сайт avtobezugona.ru.

скриншот 51

А как определить этот путь, мы рассматривали ранее во вводной статье радела "Авторизация пользователей". В которой этому вопросу была специально отведена отдельная часть Как узнать текущие настройки PHP. (В приведенном там примере для локального веб-сервера соответствующая настройка session.save_path имеет значение e:/ospanel/userdata/temp/).

На этом мы закончили создание скрипта и дополнили необходимые настройки. И теперь проверим, как это в действительности все будет работать.

Проверка работы созданного скрипта.


Для проверки работы скрипта сначала выполним следующие действия:

  • Откроем какую-нибудь страницу сайта и убедимся в том, что в папке "tmp" корневого каталога создался тестовый файл с именем "session_last_time.txt"
  • Временно, отключим управление доступом к сессии с помощью временных меток, которое мы сделали в предыдущей статье, закомментировав соответствующие фрагменты кода и изменив время жизни cookies. Иначе этот механизм сам будет удалять сессии с истекшим временем жизни, что не позволит корректно провести проверку.
  • Временно, отключим вызов пользовательской функции, закомментировав в файле check_auth.php соответствующие строки (поз.10,69, на рис.2).
  • Выполним несколько раз авторизацию, каждый раз, не выходя в ручную из сессии, дождавшись истечения ее времени жизни, в нашем случае 15 минут (для авторизации будем использовать ранее созданный аккаунт с логином Audi387357 и паролем Z5nC89).

В результате, мы должны в папке "tmp" увидеть тестовый файл вместе с сохранившимися в ней сессионными файлами с истекшим сроком, как показано на скриншоте.

Файлы истекших сессий в каталоге tmp

Рис.4 Файлы истекших сессий в каталоге "tmp"

После чего подключим вызов пользовательской функции, раскоментировав строки 10,69 в файле check_auth.php (рис.2) и обновим страницу сайта.

При правильной работе скрипта все сессионные файлы с истекшим сроком должны быть удалены. При этом должно обновиться и время модификации тестового сайта, соответствующее времени последнего очищения хранилища.

Очищенный от истекших сессий каталог tmp

Рис.5 Очищенный от истекших сессий каталог "tmp"

Как видно, все истекшие сессионные файлы удалены, что подтверждает правильную работу скрипта в этой части тестирования.

А теперь проверим период вызова функции удаления сессий и при этом убедимся в том, сборка мусора не распространяется на активные сессии.

Для этого сначала авторизуемся и зафиксируем идентификатор созданной сессии с временем последней модификации тестового файла.

Авторизация для проверки работы скрипта с активной сессией

Рис.6 Авторизация для проверки работы скрипта с активной сессией

После чего, не выходя в ручную из сессии, будем обновлять страницы сайта через определенный промежуток, например, через одну минуту.

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

Проверка работы скрипта с активной сессией

Рис.7 Проверка работы скрипта с активной сессией.

На скриншоте видно, что активная сессия сохранилась без изменения идентификатора, а время модификации тестового сайта изменилось через 15 минут после предыдущего отсчета. Что подтверждают соответствие заданной периодичности удаления истекших сессионных файлов и отсутствие какого-либо воздействия работы скрипта на активные сессии.


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

Исходные файлы сайта


Знак папкиИсходные файлы сайта с обновлениями, которые были сделаны в данной статье, можно скачать из прилагаемых дополнительных материалов:

  • Файлы каталога www
  • Таблицы базы данных MySQL

Дополнительные материалы бесплатно предоставляются только зарегистрированным пользователям.

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

Для тех кто не зарегистрирован, можно это сделать на вкладке Регистрация.

С уважением, Николай Гришин


Комментарии


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

Буду Вам за это очень признателен!

comments powered by HyperComments