Как работают сессии PHP: использование переменных, запуск и удаление

Как уничтожить сессию

В этом разделе мы увидим, как можно уничтожить сессию. В предыдущем разделе мы рассмотрели функцию unset, которая используется для удаления определённых переменных сеанса.  С другой стороны, если вы хотите удалить сразу все данные, связанные с сеансом, вы можете использовать функцию session_destroy.

Попробуем понять, как это работает в следующем примере.

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

Как правило, функцию session_destroy нужно использовать, когда пользователь выходит из системы.

Автоматический запуск сеанса

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

В файле php.ini есть параметр session.auto_start, который позволяет запускать сеанс автоматически для каждого запроса. По умолчанию установлено значение 0 (выкл), и вы можете установить его на 1 (вкл), чтобы включить функцию автоматического запуска.

С другой стороны, если у вас нет доступа к файлу php.ini, и вы используете веб-сервер Apache, эту переменную можно задать с помощью файла .htaccess.

Если вы добавите строку выше в ваш .htaccess файл, то это должно автоматически запускать сессии в вашем PHP-приложении.

Авторизация пользователя

Вопросы по авторизации пользователей с помощью PHP-сессий постоянно задаются в конференциях по
web-программированию. Механизм авторизации пользователей в системе с помощью сессий довольно хорош
с точки зрения безопасности (см.раздел Безопасность).

Безопасность

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

  • на компьютере пользователя стоит “троян”, который ворует номера сессий;
  • злоумышленник отлавливает трафик между компьютером пользователя и сервером.
    Конечно, есть защищенный (зашифрованный) протокол SSL, но им пользуются не все;
  • к компьютеру нашего пользователя подошел сосед и стащил номер сессии.

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

Впрочем, PHP очень часто можно “обмануть”. Давайте
рассмотрим возможные точки взлома в программе авторизации
пользователя:

Итак, в нашей программе явно видны две “дыры”, одна
маленькая и не особо заметная, а вот вторая – просто огромная, через
которую большинство хакеров и лезет туда, куда не надо.

Как “залатать” дыру номер 1?

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

authorize.php V2

Возможность одновременной работы в одном браузере от имени нескольких пользователей

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

В наших предыдущих примерах мы не задавали явно имя сессии, поэтому использовалось имя, установленное в PHP по умолчанию (PHPSESSID). Это значит, что все сессии, которые создавались нами до сих пор, отправляли браузеру куки под именем PHPSESSID. Очевидно, что если имя куки всегда одинаковое, то нет возможности в пределах одного браузера организовать две сессии с одинаковым именем. Но если бы мы для каждого пользователя использовали собственное имя сессии, то проблема была бы решена. Так и сделаем.

Защита сессий от несанкционированного использования

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

Сервер успешно принимает и обрабатывает этот запрос, как если бы он пришел от авторизованного пользователя. Если не реализована дополнительная проверка IP-адреса, такая атака приведет к успешному взлому аккаунта пользователя со всеми вытекающими последствиями.

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

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

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

(Опустим ту часть кода, которая уже рассмотрена).

Использование функции session_start

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

Важно, чтобы функция session_start вызывалась в начале скрипта, перед отправкой чего-либо браузеру. В противном случае, вы столкнётесь с печально известной ошибкой Headers are already sent.

Как запустить сессию

В этом разделе мы обсудим, как запустить сессию в PHP.

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

Как изменять и удалять переменные сеанса

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

Давайте посмотрим, как изменять переменные сессии.

Как получить идентификатор сессии

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

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

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

Как работать с сессиями?

Если вы будете тестировать примеры из статьи (или
ваши скрипты) на каком-либо коммерческом хостинге, проблем с работой
с сессиями быть не должно. Если же вы сами настраивали ваш сервер
(будь то реальный сервер, или эмулятор), могут появляться ошибки
примерно такого содержания:

“Warning: open(/var/state/php/sess_6f71d1dbb52fa88481e752af7f384db0, O_RDWR) failed: No such file or directory (2)”.

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

Любой скрипт, который будет использовать переменные
(данные) из сессий, должен содержать следующую
строчку:

session_start();

Эта команда говорит серверу, что данная страница
нуждается во всех переменных, которые связаны с данным пользователем
(браузером). Сервер берёт эти переменные из файла и
делает их доступными. Очень важно открыть сессию до того, как
какие-либо данные будут посылаться пользователю; на практике это
значит, что функцию session_start() желательно вызывать в самом
начале страницы, например так:

session_start();
?>
<html>
 <head>
 </head>
 ...

Для задания директории в которой будут сохраняться файлы сессий используется функция

session_save_path($_SERVER['DOCUMENT_ROOT'].'/session');
session_start();

После начала сессии можно задавать глобальные переменные.
Ари присвоении какого-либо значения любому полю массива $_SESSION,
переменная с таким же именем автоматически регистрируется, как
переменная сессии.
Этот массив доступен на всех страницах, использующих сессию. Для примера разберем програму:

index.php

Как сделать авторизацию на php? пишем авторизацию пользователя | otus

PHP_Deep_1.4-5020-7f0114.png

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

В этой статье вы узнаете, как сделать PHP-авторизацию (authentication) на сайте с помощью данных, полученных от пользователя при регистрации. Будем использовать таблицу MySQL, а сама PHP-авторизация будет работать с применением сессий и cookie. Материал не следует рассматривать, как пошаговое руководство. Зато он помогает понять, как работает PHP-авторизация в целом.

В первую очередь нужно сверстать главную страницу веб-сайта, поместив её в корне в папку template. Для этого создаём файл index.html с формой ввода логина и пароля, кнопкой «Вход», вот её код:

Мы используем метод передачи post, который необходим. Нам ведь не нужно, чтобы в процессе PHP-авторизации пароль и логин «светились» в адресной строке.

Когда форма готова, создаём главный контроллер — наиболее важный файл сайта, лежащий в корне — index.php. Как раз он и будет запускаться во время входа. Код выглядит следующим образом:

Теперь разберёмся подробнее, как всё работает.

В первых 3 строках просто подключаются файлы с функциями, необходимыми для дальнейшего использования в коде. О них поговорим потом. Далее проверяем, был ли передан get-параметрaction=out. В случае его передачи пользователь нажал на ссылку выхода с веб-сайта. Код ссылки, который нужно добавить в файл, содержащий код формы для входа:

Потом у нас идёт условие, которое проверяет, авторизован ли ты (if (login())). То есть функция возвращает нам true, если юзер вошёл на сайт. В противном случае возвращается false. Когда вернулось true, в переменную $UID записывается id юзера. Что касается переменной $admin, то в неё пишется результат работы функции is_admin($UID). Она определяет, является ли наш юзер админом, возвращая true, если это так и false в обратном случае. Потом эти 2 переменные понадобятся, чтобы вывести определённые элементы на странице.

Итак, форму PHP-авторизации можно вывести следующим условием:

Аналогичная ситуация и с переменной $admin. Последний код тоже можно поместить в файл с формой.

Если функция login() вернёт false (юзер не вошёл на сайт), мы проверим, а нажал ли он вообще на кнопку входа на сайт, которая включена в нашу форму PHP-авторизации:

Если это так, запускается функция enter(), авторизующая пользователя. Если ошибки отсутствуют, а пользователь вошёл успешно, создаём те же две переменные: $UID и $admin. В обратном случае переменные не создаются никакие, ведь пользователь является гостем.

Давайте посмотрим на алгоритм работы:

1-20219-6acf0c.jpg

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

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

Но если работа функции enter() будет продолжена, мы проверим, а существует ли в базе данных запись с таким ником. Когда записи нет, возвращается массив с ошибкой. Когда есть, введённый пароль сравнивается со значением, которое хранится в БД.

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

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

Давайте подробно остановимся на том, что значит «авторизироваться». В нашем скрипте информация о PHP-авторизации хранится в cookie и сессии. В сессию записывается id пользователя:

Кроме того, создаются 2 cookie: login и password. Продолжительность жизни — 50 тыс. секунд. В первый пишется логин, во 2-й — хэш пароля.

В данной строке выполняется функция, которая устанавливает время последней активности юзера. Код:

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

Теперь посмотрим на алгоритм работы функции enter():

2-20219-e35f69.jpg

Идём дальше. Следующая функция нужна для проверки, авторизирован ли юзер на сайте — login().

functionlogin(){ini_set("session.use_trans_sid",true);session_start();if(isset($_SESSION['id']))//если сесcия есть   {if(isset($_COOKIE['login'])&&isset($_COOKIE['password']))//если cookie есть, обновляется время их жизни и возвращается true      {           SetCookie("login","",time()-1,'/');SetCookie("password","",time()-1,'/');setcookie("login",$_COOKIE['login'],time() 50000,'/');setcookie("password",$_COOKIE['password'],time() 50000,'/');$id=$_SESSION['id'];lastAct($id);returntrue;}else//иначе добавляются cookie с логином и паролем, чтобы после перезапуска браузера сессия не слетала         {$rez=mysql_query("SELECT * FROM users WHERE id='{$_SESSION['id']}'");//запрашивается строка с искомым id             if(mysql_num_rows($rez)==1)//если получена одна строка          {       $row=mysql_fetch_assoc($rez);//она записывается в ассоциативный массив               setcookie("login",$row['login'],time() 50000,'/');setcookie("password",md5($row['login'].$row['password']),time() 50000,'/');$id=$_SESSION['id'];lastAct($id);returntrue;}elsereturnfalse;}}else//если сессии нет, проверяется существование cookie. Если они существуют, проверяется их валидность по базе данных     {if(isset($_COOKIE['login'])&&isset($_COOKIE['password']))//если куки существуют      {$rez=mysql_query("SELECT * FROM users WHERE login='{$_COOKIE['login']}'");//запрашивается строка с искомым логином и паролем             @$row=mysql_fetch_assoc($rez);if(@mysql_num_rows($rez)==1&&md5($row['login'].$row['password'])==$_COOKIE['password'])//если логин и пароль нашлись в базе данных           {$_SESSION['id']=$row['id'];//записываем в сесиию id              $id=$_SESSION['id'];lastAct($id);returntrue;}else//если данные из cookie не подошли, эти куки удаляются             {SetCookie("login","",time()-360000,'/');SetCookie("password","",time()-360000,'/');returnfalse;}}else//если куки не существуют      {returnfalse;}}}

Возникает вопрос, почему для авторизации используем и сессию, и cookie? Всё дело в том, что при закрытии браузера сессия «умирает», а пользователь автоматически разлогинивается. А вот cookie хранятся определённое время, задаваемое нами (50 тыс. секунд).

Дальше у нас функция online(). Её нужно запускать первой на всех модулях и страницах будущего сайта. В первую очередь, она проверяет, прошёл ли пользователь PHP-авторизацию/аутентификацию, что важно для дальнейшей работы скрипта. Во вторую очередь, она выполняет обновление времени последней активности, а также помогает в перспективе выводить систему онлайн-пользователей.

Наша функция вернёт true, когда юзер авторизирован, а в обратном случае — false. При этом в процессе работы обновится время жизни cookie или они будут созданы, если вообще не существуют.

Очередной алгоритм работы:

3-20219-7b542b.jpg

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

Когда сессия есть, а cookie почему то нет, то по id юзера мы получаем из базы данных логин и хэш пароля, потом пишем их в cookie. Возвращается true.

Когда сессии нет, проверяем, существуют ли cookie. Традиционный пример — PHP-авторизация после перезапуска браузера, когда сессия слетела, но cookie всё ещё живы. Становится сложнее, ведь нужно проверить, а совпадает ли пара пароль-логин с какой-нибудь строкой из базы данных. Ведь пользователь легко мог сменить cookie в настройках для сайта. Если пара нашлась, создаётся переменная сессии, возвращается true. Если пара не нашлась, возвращается false.

Если у нас самый печальный вариант — ни сессии, ни cookie не оказалось, возвращается false.

Сейчас глянем на функцию is_admin($UID), определяющую является ли user админом. Если вам это не надо, опустите данную функцию и её вызовы в контроллере. Но учтите, что для вывода контента на страницу для админов она бывает полезна. К тому же, она проста и основана на одном столбце в базе данных в таблице users (столбец prava, тип int).

Когда наш юзер обыкновенный пользователь, значению в столбце присваивается 0, иначе — 1. Соответственно, в первом случае вернётся false, во втором — true.

Последняя функция — это out(). Она проста и удаляет все «следы» юзера — и сессию, и cookie.

Код всех наших функций нужно поместить в файл lib/module_global.php, подключаемый в начале работы контроллера.

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

Источник: https://true-coder.ru/php/pishem-avtorizaciyu-na-php.html.

Контроль отсутствия активности пользователя с помощью сессионных переменных

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

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

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

Создание переменных сеанса

В этом разделе мы изучим, как инициализировать переменные сессии в PHP.

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

Давайте рассмотрим следующий пример кода, который показывает, как инициализировать переменные сеанса.

Создание формы авторизации

Теперь перейдем непосредственно к самой авторизации. Создайте файл с названием mylogin.html со следующим содержанием:

Создание формы регистрации

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

Заключение

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

Похожее:  Деавторизация и авторизация компьютера | Всё об iPad

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *