Reg.ru: домены и хостинг
Крупнейший регистратор и хостинг-провайдер в России.
Более 2 миллионов доменных имен на обслуживании.
Продвижение, почта для домена, решения для бизнеса.
Более 700 тыс. клиентов по всему миру уже сделали свой выбор.
*Наведите курсор мыши для приостановки прокрутки.
Назад Вперед
Создание простой системы регистрации пользователей на PHP и MySQLСоздание системы регистрации - это большая работа. Вам приходится писать код, который осуществляет валидацию email-адресов, отправляет сообщение на почту с подтверждением регистрации, а также осуществляет валидацию остальных полей формы, и много ещё всего.
И даже после того как вы всё это напишите, пользователи будут регистрироваться неохотно, т.к. это требует определённых усилий с их стороны.
В этом уроке, мы создадим очень простую систему регистрации, которая не требует и не хранит паролей вообще! Результат будет легко изменить и добавить к уже существующему PHP-сайту. Хотите выяснить, как это работает? Читайте ниже.
Вот как наша супер простая система будет работать:
Мы скомбинируем форму авторизации и регистрацию. В этой форме будет поле для ввода email-адреса и кнопка регистрации;
- При заполнении поля email-адресом, по нажатию на кнопку регистрации будет создана запись о новом пользователе, но только в том случае, если введённого email-адреса не было найдено в базе данных.
После этого создаётся некий случайный уникальный набор символов (токен), который отправляется на указанную пользователем почту в виде ссылки, которая будет актуальна в течение 10 минут;
- По ссылке пользователь переходит на наш сайт. Система определяет наличие токена и авторизует пользователя;
Преимущества такого подхода:
Не нужно хранить пароли и осуществлять валидацию полей;
- Нет необходимости в восстановлении пароля, секретных вопросов и т.д.;
- С момента как пользователь зарегистрировался/авторизовался вы можете всегда быть уверены, что этот пользователь будет в вашей зоне доступа (что email-адрес является истинным);
- Невероятно простой процесс регистрации;
Недостатки:
Безопасность аккаунта пользователя. Если кто-то имеет доступ к почте пользователя, он может авторизоваться.
- Email не защищён и может быть перехвачен. Имейте в виду, что этот вопрос актуален и в случае, когда пароль был забыт и его необходимо восстановить, или в любой системе авторизации, которая не использует HTTPS для передачи данных (логин/пароль);
- Пока вы настроите как нужно почтовый сервер, существует шанс, что сообщения со ссылками на авторизацию будут попадать в спам;
Сравнивая преимущества и недостатки нашей системы, можно сказать, что система имеет высокое юзабилити (максимально удобна для конечного пользователя) и, в то же время, имеет невысокий показатель безопасности.
Так что использовать её предлагается для регистраций на форумах и сервисах, которые не работают с важной информацией.
Как пользоваться этой системой
В случае, когда вам нужно просто использовать систему для авторизации пользователей на вашем сайте, и вам не хочется разбирать данный урок по косточкам, вот что вам нужно сделать:
Вам нужно скачать исходники, приложенные к уроку
- В архиве найти файл tables.sql
Импортируйте его в вашу базу данных используя опцию импорта в phpMyAdmin. Альтернативный способ: открыть этот файл через текстовый редактор, скопировать SQL запрос и выполнить его;
- Открыть includes/main.php
и заполнить настройки связи с вашей базой данных (указать пользователя и пароль для связи с базой а также хост и имя базы). В этом же файле, вы также должны указать email, который будет использован в качестве оригинального адреса для сообщений отправляемых системой. Некоторые хосты блокируют исходящие мейлы пока в форме не будет указан настоящий email адрес, который был создан из панели управления хостом, так что укажите реальный адрес;
- Загрузите все файлы index.php
, protected.php
и папки assets и includes через FTP на ваш хост;
- Добавьте код ниже на каждую PHP-страницу, где нужно отобразить форму авторизации;
Require_once "includes/main.php";
$user = new User();
if(!$user->loggedIn()){
redirect("index.php");
}
- Готово!
Для тех же, кому интересно, как это всё работает - вперёд к чтению ниже!
Первый шаг - написание HTM- кода формы авторизации. Данный код располагается в файле index.php . Этот файл также содержит PHP-код, обрабатывающий данные формы и другие полезные функции системы авторизации. Узнать об этом больше можно в разделе ниже, посвящённом обзору PHP кода.
index.php
Tutorial: Super Simple Registration System With PHP & MySQL Login or Register
Enter your email address above and we will send
you a login link.
В головной секции (между тегами и ) я подключил основные стили (в этом уроке они не разбираются, поэтому вы можете посмотреть их сами. Папка assets/css/style.css). До закрывающего тега я подключил библиотеку jQuery и файл script.js, который мы напишем и разберём чуть ниже.
JavaScript
jQuery отслеживает состояние кнопки "Зарегистрироваться/авторизоваться" с помощью функции e.preventDefault() и отправляет AJAX-запросы. В зависимости от ответа сервера, выводит то или иное сообщение и определяет дальнейшие действия/
assets/js/script.js
$(function(){ var form = $("#login-register"); form.on("submit", function(e){ if(form.is(".loading, .loggedIn")){ return false; } var email = form.find("input").val(), messageHolder = form.find("span"); e.preventDefault(); $.post(this.action, {email: email}, function(m){ if(m.error){ form.addClass("error"); messageHolder.text(m.message); } else{ form.removeClass("error").addClass("loggedIn"); messageHolder.text(m.message); } }); }); $(document).ajaxStart(function(){ form.addClass("loading"); }); $(document).ajaxComplete(function(){ form.removeClass("loading"); }); });
был добавлен в форму для отображения текущего состояния AJAX-запроса (это стало возможным благодаря методам ajaxStart() ) и ajaxComplete() , которые вы сможете найти ближе к концу файла).Этот класс показывает крутящийся анимированный gif-файл (как бы намекающий нам на то, что запрос обрабатывается), и также выступает как флаг, предотвращающий повторную отправку формы (когда кнопка зарегистрироваться была уже однажды нажата). Класс .loggedIn - это другой флаг, - устанавливается тогда, когда был отправлен email. Этот флаг моментально блокирует любые дальнейшие действия с формой.
Схема базы данных
Наша невероятно простая система регистрации использует 2 MySQL таблицы (SQL-код находится в файле tables.sql ). Первая хранит данные об аккаунтах пользователей. Вторая хранит информацию о количестве попыток входа.
Схема таблицы пользователей.
Система не использует паролей, что видно на схеме. На ней же можно увидеть колонку token с токенами, соседствующую с колонкой token_validity . Токен устанавливается как только пользователь подключается к системе, задаёт свой email для отправки сообщения (чуть подробнее об этом в следующем блоке). Колонка token_validity устанавливает время на 10 минут позже, после которого токен перестаёт быть актуальным.
Схема таблицы, считающая количество попыток авторизации.
В обоих таблицах IP-адрес хранится в обработанном виде, с помощью функции ip2long в поле типа integer.
Теперь мы можем написать немножко PHP-кода. Основной функционал системы возложен на класс User.class.php , который вы можете видеть ниже.
Данный класс активно использует idorm (docs), эти библиотеки являются минимально необходимыми инструментами, для работы с базами данных. Он обрабатывает доступ к базе данных, генерацию токенов и их валидацию. Он представляет собой простой интерфейс, позволяющий легко подключить систему регистрации к вашему сайту, если он использует PHP.
User.class.php
Class User{ // Частный ORM случай private $orm; /** * Найти пользователя по токену. Только валидные токены, приняты к рассмотрению. Токен генерируется только на 10 минут с того момента как был создан * @param string $token. Это искомый токен * @return User. Вернуть значение функции User */ public static function findByToken($token){ // найти токен в базе и убедиться, что установлен корректный временной штамп $result = ORM::for_table("reg_users") ->where("token", $token) ->where_raw("token_validity > NOW()") ->find_one(); if(!$result){ return false; } return new User($result); } /** * Авторизовать или зарегистрировать пользователя * @param string $email. Пользовательский email-адрес * @return User */ public static function loginOrRegister($email){ // Если такой пользователь уже существует, вернуть значение функции User от заданного email-адреса хранимого в базе if(User::exists($email)){ return new User($email); } // В противном случае создать нового пользователя в базе и вернуть значение функции User::create от указанного email return User::create($email); } /** * Создать нового пользователя и сохранить в базу * @param string $email. Пользовательский email-адрес * @return User */ private static function create($email){ // Записать нового пользователя и вернуть результат функции User от этих значений $result = ORM::for_table("reg_users")->create(); $result->email = $email; $result->save(); return new User($result); } /** * Проверить, существует ли такой пользователь в базе и вернуть булево значение переменной * @param string $email. Пользовательский email-адрес * @return boolean */ public static function exists($email){ // Существует ли пользователь в базе? $result = ORM::for_table("reg_users") ->where("email", $email) ->count(); return $result == 1; } /** * Создать новый пользовательский объект * @param экземпляр $param ORM , id, email or 0 * @return User */ public function __construct($param = null){ if($param instanceof ORM){ // ORM проверка пройдена $this->orm = $param; } else if(is_string($param)){ // Проверка на email пройдена $this->orm = ORM::for_table("reg_users") ->where("email", $param) ->find_one(); } else{ $id = 0; if(is_numeric($param)){ // идентификатору пользователя передаётся значение переменной $param $id = $param; } else if(isset($_SESSION["loginid"])){ // В противном случае смотри сессию $id = $_SESSION["loginid"]; } $this->orm = ORM::for_table("reg_users") ->where("id", $id) ->find_one(); } } /** * Сгенерировать новый SHA1 токен авторизации, записывает в базу и возвращает его значение * @return string */ public function generateToken(){ // Сгенерировать токен для авторизованного пользователя и сохранить его в базу $token = sha1($this->email.time().rand(0, 1000000)); // Сохранить токен в базе // И пометить его, что он актуален только в течение 10 следующих минут $this->orm->set("token", $token); $this->orm->set_expr("token_validity", "ADDTIME(NOW(),"0:10")"); $this->orm->save(); return $token; } /** * Авторизовать пользователя * @return void */ public function login(){ // Отметить пользователя, как авторизованного $_SESSION["loginid"] = $this->orm->id; // Обновить значение поля базы last_login $this->orm->set_expr("last_login", "NOW()"); $this->orm->save(); } /** * Уничтожить сессию и разлогинить пользователя * @return void */ public function logout(){ $_SESSION = array(); unset($_SESSION); } /** * Проверка, заходил ли пользователь * @return boolean */ public function loggedIn(){ return isset($this->orm->id) && $_SESSION["loginid"] == $this->orm->id; } /** * Проверка является ли пользователь администратором * @return boolean */ public function isAdmin(){ return $this->rank() == "administrator"; } /** * Найти тип пользователя, может быть либо administrator либо regular * @return string */ public function rank(){ if($this->orm->rank == 1){ return "administrator"; } return "regular"; } /** * Метод позволяющий получить приватную информацию пользователя в *качестве свойств объекта User * @param string $key Имя свойства, получающего доступ * @return mixed */ public function __get($key){ if(isset($this->orm->$key)){ return $this->orm->$key; } return null; } }
Токены генерируются с помощью SHA1 алгоритма и сохраняются в базе данных. Я использую функции времени MySQL, дабы задать 10-минутное ограничение актуальности токена.
Когда токен проходит процедуру валидации, мы напрямую говорим обработчику, что мы рассматриваем только токены, у которых ещё не истёк срок годности, хранимый в столбце token_validity.
Обратите внимание, что я использую волшебный метод __get библиотеки docs в конце файла, чтобы перехватить доступ к свойствам объекта User.
Благодаря этому становится возможным получить доступ к информации, хранящейся в базе, благодаря свойствам $user->email, $user->token и др. В следующем фрагменте кода рассмотрим для примера, как использовать эти классы.
Защищённая страница
Ещё один файл, хранящий полезный и необходимый функционал - это файл functions.php . Здесь есть несколько так называемых хелперов - функций-помощников, которые позволяют создавать более чистый и читабельный код в других файлах.
functions.php
Function send_email($from, $to, $subject, $message){ // Хелпер, отправляющий email $headers = "MIME-Version: 1.0" . "\r\n"; $headers .= "Content-type: text/plain; charset=utf-8" . "\r\n"; $headers .= "From: ".$from . "\r\n"; return mail($to, $subject, $message, $headers); } function get_page_url(){ // Определить URL PHP-файла $url = "http".(empty($_SERVER["HTTPS"])?"":"s")."://".$_SERVER["SERVER_NAME"]; if(isset($_SERVER["REQUEST_URI"]) && $_SERVER["REQUEST_URI"] != ""){ $url.= $_SERVER["REQUEST_URI"]; } else{ $url.= $_SERVER["PATH_INFO"]; } return $url; } function rate_limit($ip, $limit_hour = 20, $limit_10_min = 10){ // Количество попыток входа за последний час по этому IP-адресу $count_hour = ORM::for_table("reg_login_attempt") ->where("ip", sprintf("%u", ip2long($ip))) ->where_raw("ts > SUBTIME(NOW(),"1:00")") ->count(); // Количество попыток входа за последние 10 минут по этому IP-адресу $count_10_min = ORM::for_table("reg_login_attempt") ->where("ip", sprintf("%u", ip2long($ip))) ->where_raw("ts > SUBTIME(NOW(),"0:10")") ->count(); if($count_hour > $limit_hour || $count_10_min > $limit_10_min){ throw new Exception("Too many login attempts!"); } } function rate_limit_tick($ip, $email){ // Создать новую запись в таблице, считающей количество попыток входа $login_attempt = ORM::for_table("reg_login_attempt")->create(); $login_attempt->email = $email; $login_attempt->ip = sprintf("%u", ip2long($ip)); $login_attempt->save(); } function redirect($url){ header("Location: $url"); exit; }
Функции rate_limit и rate_limit_tick следят за количеством попыток авторизации за истёкший период времени с момента первой попытки. Попытка входа записывается в базе в столбец reg_login_attempt. Эти функции вызываются когда происходит обработка и отправка данных формы как вы можете видеть из следующего фрагмента кода.
Код ниже взят из файла index.php и он обрабатывает отправку формы. Он возвращает JSON-ответ, который, в свою очередь, обрабатывается jQuery в файле assets/js/script.js , который мы уже разбирали ранее.
index.php
Try{ if(!empty($_POST) && isset($_SERVER["HTTP_X_REQUESTED_WITH"])){ // Output a JSON header header("Content-type: application/json"); // Является ли этот email-адрес валидным if(!isset($_POST["email"]) || !filter_var($_POST["email"], FILTER_VALIDATE_EMAIL)){ throw new Exception("Please enter a valid email."); } // Проверка. Позволено ли пользователю авторизоваться, не превысил ли он количество допустимых подключений? (файл functions.php для большей информации) rate_limit($_SERVER["REMOTE_ADDR"]); // Записать эту попытку авторизации rate_limit_tick($_SERVER["REMOTE_ADDR"], $_POST["email"]); // Отправить письмо пользователю $message = ""; $email = $_POST["email"]; $subject = "Your Login Link"; if(!User::exists($email)){ $subject = "Thank You For Registering!"; $message = "Thank you for registering at our site!\n\n"; } // Попытка авторизовать или зарегистрировать пользователя $user = User::loginOrRegister($_POST["email"]); $message.= "You can login from this URL:\n"; $message.= get_page_url()."?tkn=".$user->generateToken()."\n\n"; $message.= "The link is going expire automatically after 10 minutes."; $result = send_email($fromEmail, $_POST["email"], $subject, $message); if(!$result){ throw new Exception("There was an error sending your email. Please try again."); } die(json_encode(array("message" => "Thank you! We\"ve sent a link to your inbox. Check your spam folder as well."))); } } catch(Exception $e){ die(json_encode(array("error"=>1, "message" => $e->getMessage()))); }
После успешной авторизации/регистрации код выше отправит пользователю ссылку для авторизации. Токен становится доступным, т.к. он передаётся в качестве переменной в генерируемой ссылке методом $_GET с маркером tkn
index.php
If(isset($_GET["tkn"])){ // Является ли этот токен валидным для авторизации? $user = User::findByToken($_GET["tkn"]); if($user){ // Да, является. Осуществить редирект на защищённую страницу $user->login(); redirect("protected.php"); } // Нет, токен не валидный. Осуществить редирект, на страницу с формой авторизации/регистрации redirect("index.php"); }
$user->login()
создаст необходимые переменные для сессии, так что пользователь, просматривая последующие страницы сайта, будет всё время оставаться авторизованным.
Похожим образом устроена и обработка функции на выход из системы.
index.php
If(isset($_GET["logout"])){ $user = new User(); if($user->loggedIn()){ $user->logout(); } redirect("index.php"); }
В конце кода, я снова поставил редирект на index.php, таким образом параметр ?logout=1 передаваемый посредством URL не требуется.
Наш файл index.php требует доп. защиты - мы не хотим, чтобы люди, которые когда-либо однажды авторизовались в системе опять видели форму регистрации. Для этих целей, мы используем метод $user->loggedIn() .
index.php
$user = new User(); if($user->loggedIn()){ redirect("protected.php"); }
Наконец-то, вот кусок кода, позволяющий защитить страницы вашего сайта и сделать её доступной только после авторизации.
protected.php
// Чтобы защитить каждую страницу на вашем сайте подключите к ней файл // main.php и создайте новый объект User. Вот как это просто! require_once "includes/main.php"; $user = new User(); if(!$user->loggedIn()){ redirect("index.php"); }
После этой проверки можете быть уверенными, что пользователь был успешно авторизован. Вы также можете получить доступ к хранимой информации в базе с помощью свойств объекта $user . Для вывода email-а пользователя и его статуса используйте этот код:
Echo "Your email: ".$user->email; echo "Your rank: ".$user->rank();
Метод rank() используется здесь потому что в базе обычно хранятся номера (0 для обычного пользователя, 1 для администратора) и нам нужно преобразовать эти данные в статусы, к которым они относятся, в чём нам и помогает этот метод.
Чтобы сделать из обычного пользователя администратора, просто отредактируйте пользовательскую запись через phpMyAdmin (или любую другую программу, позволяющую управлять базами данных). Статус администратора не даёт каких-либо привилегий, в данном примере на странице будет выведено, что вы администратор - и всё.
А вот что с этим делать - остаётся уже на ваше усмотрение, вы можете сами написать и составить код, задающий определённые привилегии и возможности для администраторов.
Мы закончили!
С этой невероятно супер квази простой формой мы закончили! Вы можете использовать её в ваших PHP-сайтах, это достаточно просто. Также вы можете модифицировать её под себя и сделать её такой, как вы хотите.
Материал подготовил Денис Малышок специально для сайта сайт
P.S. Хотите двигаться дальше в освоении PHP и ООП? Обратите внимание на премиум-уроки по различным аспектам сайтостроения, включая программирование на PHP, а также на бесплатный курс по созданию своей CMS-системы на PHP с нуля с использованием ООП:
Понравился материал и хотите отблагодарить?
Просто поделитесь с друзьями и коллегами!
С самого начала PHP все приняли на ура, но как только на этом языке стали создавать достаточно крупные проекты, разработчики столкнулись с новой проблемой - в PHP отсутствовало понятие глобальных переменных! То есть, выполнялся некий скрипт, посылал сгенерированную страницу клиенту, и все ресурсы, используемые этим скриптом уничтожались. Попробую проиллюстрировать: предположим есть две страницы одного сайта, index.php и dothings.php. Исходники к этим страницам выглядят так:
index.php dothings.phpЕсли выполнить эти два скрипта, то на первой странице мы увидим надпись "Меня задали на index.php", а вторая страница будет пустой.
Разработчики web-сайтов, недолго думая, стали использовать cookie для хранения глобальных переменных на стороне клиента. Процесс выглядел примерно так: пользователь приходит на главную страницу сайта, делает какие-то действия, и вся информация, связанная с этим пользователем, которая может потребоваться на других страницах сайта, будет храниться у него в браузере в виде cookie. Этот метод имеет довольно серьезные минусы, из-за которых от PHP в своё время отвернулось немало разработчиков. Например, нам нужно авторизовать пользователя, чтобы разрешить ему доступ к закрытым (или принадлежащим только ему) разделам сайта. Придется отправлять пользователю cookie, который будет служит его последующим идентификатором на сайте. Такой подход становится очень громоздким и не удобным, как только сайт начинает собирать всё больше и больше сведений о поведении пользователя, ведь всю информацию, посылаемую пользователю, желательно кодировать, чтобы её нельзя было подделать. Ещё совсем недавно подделкой cookie можно было "уложить" не один чат, а порой и пробраться в чужую почту. К тому же есть ещё на свете странные люди, у которых браузер cookie не поддерживает.
Я не буду вдаваться в технологические вопросы устройства механизма работы сессий, а только опишу, как правильно работать с сессиями в PHP.
Как работать с сессиями?Если вы будете тестировать примеры из статьи (или ваши скрипты) на каком-либо коммерческом хостинге, проблем с работой с сессиями быть не должно. Если же вы сами настраивали ваш сервер (будь то реальный сервер, или эмулятор), могут появляться ошибки примерно такого содержания:
"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(); ?> ... Для задания директории в которой будут сохраняться файлы сессий используется функция session_save_path() : session_save_path($_SERVER["DOCUMENT_ROOT"]."/session"); session_start();
После начала сессии можно задавать глобальные переменные. Ари присвоении какого-либо значения любому полю массива $_SESSION, переменная с таким же именем автоматически регистрируется, как переменная сессии. Этот массив доступен на всех страницах, использующих сессию. Для примера разберем програму:
index.php Всё ОК. Сессию загрузили! Пройдём, посмотрим что там: dothings.phpПри последовательном запуске этих файлов, первый скрипт "index.php" выдаст следующий результат:
Всё ОК. Сессию загрузили! Пройдём, посмотрим что там:А второй "dothings.php" вот это:
Меня задали на index.phpПеременная $a теперь доступна на всех страницах данного сайта, которые запустили сессии.
Другие полезные функции и приемы для работы с сессиями:
- unset($_SESSION["a"]) - сессия "забывает" значение заданной сессионой переменной;
- session_destroy () - сессия уничтожается (например, если пользователь покинул систему, нажав кнопку "выход");
- session_set_cookie_params (int lifetime [, string path [, string domain]]) - с помощью этой функции можно установить, как долго будет "жить" сессия, задав unix_timestamp определяющий время "смерти" сессии. По умолчанию, сессия "живёт" до тех пор, пока клиент не закроет окно браузера.
- session_write_close () - запись переменных сесии и закрытие ее. Это необходимо для открытия сайта в новом окне, если страница выполняет длительную обработу и заблокировала для вашего браузера файл сессий.
Теперь обратимся к практическому применению механизма сессий. Здесь мы рассмотрим пару довольно простых и в то же время полезных примеров.
Авторизация ПользователяВопросы по авторизации пользователей с помощью PHP-сессий постоянно задаются в конференциях по web-программированию. Механизм авторизации пользователей в системе с помощью сессий довольно хорош с точки зрения безопасности (см.раздел ).
Наш пример будет состоять из трёх файлов: index.php, authorize.php и secretplace.php. Файл index.php содержит форму, где пользователь введёт свой логин и пароль. Эта форма передаст данные файлу authorize.php, который в случае успешной авторизации допустит пользователя к файлу secretplace.php, а в противном случае выдаст сообщение об ошибке.
Примеры: index.php
Вводи пароль
Логин:
Пароль:
authorize.php
Вы ввели неверный пароль!
secretplace.php
Привет, , ты на секретной странице!!! :)
Итак, мы умеем передавать идентификатор от одной страницы (PHP-скрипта) к другой (до следующего вызова с нашего сайта), а значит мы можем различать всех посетителей сайта. Так как идентификатор сессии - это очень большое число (128 бит), шансов, что его удастся подобрать перебором, практически нет. Поэтому злоумышленнику остаются следующие возможности:
- на компьютере пользователя стоит "троян", который ворует номера сессий;
- злоумышленник отлавливает трафик между компьютером пользователя и сервером. Конечно, есть защищенный (зашифрованный) протокол SSL, но им пользуются не все;
- к компьютеру нашего пользователя подошел сосед и стащил номер сессии.
Такие ситуации, основанные на том, что кто-то что-то у кого-то стащит, в общем, не входят в компетенцию программиста. Об этом должны заботиться администраторы и сами пользователи.
Впрочем, PHP очень часто можно "обмануть". Давайте рассмотрим возможные точки взлома в программе авторизации пользователя:
- Файл authorize.php - попытка подбора пароля с помощью стороннего скрипта;
- Файл secretplace.php - попытка обмануть программу путём вписывания значений переменной
$logged_user в адресной строке браузера, например так:
"http://www.yoursite.ru/secretplace.php?logged_user=hacker "
Итак, в нашей программе явно видны две "дыры", одна маленькая и не особо заметная, а вот вторая - просто огромная, через которую большинство хакеров и лезет туда, куда не надо.
Как "залатать" дыру номер 1?Не будем писать тонны кода по блокировке IP-адреса и т.п., а просто проверим, откуда приходит запрос, а точнее с какой страницы пришёл запрос, если это будет любая страница с нашего сайта, то всё нормально, а во всех остальных случаях пускать не будем. Подкорректируем файл authorize.php:
authorize.php V2 Вы ввели неверный пароль!Как избавиться от "дыры" номер 2?
Предположим, у вас есть сайт, где каждый смертный может зарегистрироваться чтобы добавлять сообщения в форум. Естественно, в форуме у некоторых пользователей (админов, модераторов), возможностей больше чем у других, они, например, могут удалять сообщения других пользователей. Уровень доступа пользователя вы храните в сессии, в переменной $user_status, где $user_status = 10 соответствует полному доступу к системе. Пришедшему на сайт злоумышленнику достаточно зарегистрироваться штатным образом, а потом дописать в адресной строке браузера ?user_status=10 . Вот и завёлся у вас на форуме новый админ!
В принципе, любую переменную скрипта можно задать через адресную строку, просто дописав после полного адреса к скрипту вопросительный знак и название переменной с её значением. Давайте поправим наш код, чтобы этого избежать:
secretplace.php V2 Привет, , ты на секретной странице! ИтогиМеханизм сессий - довольно удачная особенность языка PHP. Сессии просты, очень гибки в использовании. Кстати, есть одна, мало где документированная возможность сессий PHP (доступна начиная с версии 4.0.3) - в сессиях можно хранить не только переменные, но и объекты.
Примеры ?>// Автоматическая вставка SID в ссылки. ini_set("session.use_trans_sid", true); session_start(); ?> Click here!
Click here!!
// Пример работы с сессиями. session_start(); // Если на сайт только-только зашли, обнуляем счетчик. if (!isset($_SESSION["count"])) $_SESSION["count"] = 0; // Увеличиваем счетчик в сессии. $_SESSION["count"] = $_SESSION["count"] + 1; ?> Счетчик раз(а).
Закройте браузер, чтобы обнулить счетчик.