- Безопасный метод авторизации на PHP
- Модель авторизации:
- Реализация
- Регистрация и Авторизация на PHP + MySQL
- Условия для регистрации пользователей
- Структура таблицы: bez_reg
- Теперь создадим основные скрипты для дальнейшей работы.
- Файл INDEX.PHP
- Файл CONFIG.PHP
- Файл 404.HTML
- Файл BD.PHP
- Файл INDEX.HTML
- Файл FUNCT.PHP
- Файл REG.PHP
- Файл REG_FORM.HTML
- Файл AUTH.PHP
- Файл AUTH_FORM.HTML
- Файл SHOW.PHP
- Архив обновлен 24.02.2015г.
Безопасный метод авторизации на PHP
Давайте посмотрим вокруг: форумы, интернет магазины, гостевые книги и т.д. используют регистрацию и последующую авторизацию пользователей. Можно даже сказать, что это почти необходимая функция каждого сайта (только если это не домашняя страничка Васи Пупкина или не визитная карточка, какой-нибудь небольшой компании). Сегодня я хочу поделиться со всеми новичками информацией, о том, как лучше это все реализовать.
Модель авторизации:
Клиент
Сервер MySQL
Таблица users
user_id (int(11))
user_login (Varchar(30))
user_password (varchar(32))
user_hash (varchar(32))
user_ip (int(10)) по умолчанию 0
При регистрации в базу данных записывается логин пользователя и пароль(в двойном md5 шифровании).
При авторизации сравнивается логин и пароль, если они верны, то генерируется случайная строка, которая хешируется и добавляется в БД в строку user_hash. Также записывается IP-адрес пользователя (но это у нас будет опциональным, так как кто-то сидит через Proxy, а у кого-то IP динамический. тут уже пользователь сам будет выбирать безопасность или удобство). В куки пользователя мы записываем его уникальный индетификатор и сгенерированный hash.
Почему надо хранить в куках хеш случайно сгенерированной строки, а не хеш пароля?
- Из-за невнимательности программиста во всей системе могут быть дырки, воспользовавшись этими дырками, злоумышленик может вытащить хеш пароля из БД и подставить его в свои куки, тем самым получить доступ к закрытым данным. В нашем же случае двойной хеш пароля ничем не сможет помочь хакеру, так как расшифровать его он не сможет (теоретически это возможно, но на это он потратит не один месяц, а может быть, и год), а воспользоваться этим хешем ему негде, ведь у нас при авторизации свой уникальный хеш прикрепленный к IP пользователя.
- Если злоумышленик вытащит трояном у пользователя уникальный хеш, воспользоваться им он также не сможет (разве, если только пользователь решил пренебречь своей безопастностью и выключил привязку к IP при авторизации).
Реализация
Структура таблицы `users` в базе данных ‘testtable’
CREATE TABLE `users` ( `user_id` int(11) unsigned NOT NULL auto_increment, `user_login` varchar(30) NOT NULL, `user_password` varchar(32) NOT NULL, `user_hash` varchar(32) NOT NULL default '', `user_ip` int(10) unsigned NOT NULL default '0', PRIMARY KEY (`user_id`) ) ENGINE=MyISAM DEFAULT CHARSET=cp1251 AUTO_INCREMENT=1 ;
register.php
if(strlen($_POST[‘login’]) < 3 or strlen($_POST['login']) >30) < $err[] = "Логин должен быть не меньше 3-х символов и не больше 30"; >// проверяем, не сущестует ли пользователя с таким именем $query = mysqli_query($link, «SELECT user_id FROM users WHERE user_login='».mysqli_real_escape_string($link, $_POST[‘login’]).»‘»); if(mysqli_num_rows($query) > 0) < $err[] = "Пользователь с таким логином уже существует в базе данных"; >// Если нет ошибок, то добавляем в БД нового пользователя if(count($err) == 0) < $login = $_POST['login']; // Убераем лишние пробелы и делаем двойное хеширование $password = md5(md5(trim($_POST['password']))); mysqli_query($link,"INSERT INTO users SET user_login='".$login."', user_password='".$password."'"); header("Location: login.php"); exit(); >else < print "При регистрации произошли следующие ошибки:
«; foreach($err AS $error) < print $error."
«; > > > ?> Логин
Пароль
return $code; > // Соединямся с БД $link=mysqli_connect(«localhost», «mysql_user», «mysql_password», «testtable»); if(isset($_POST[‘submit’])) < // Вытаскиваем из БД запись, у которой логин равняеться введенному $query = mysqli_query($link,"SELECT user_id, user_password FROM users WHERE user_login='".mysqli_real_escape_string($link,$_POST['login'])."' LIMIT 1"); $data = mysqli_fetch_assoc($query); // Сравниваем пароли if($data['user_password'] === md5(md5($_POST['password']))) < // Генерируем случайное число и шифруем его $hash = md5(generateCode(10)); if(!empty($_POST['not_attach_ip'])) < // Если пользователя выбрал привязку к IP // Переводим IP в строку $insip = ", user_ip=INET_ATON('".$_SERVER['REMOTE_ADDR']."')"; >// Записываем в БД новый хеш авторизации и IP mysqli_query($link, «UPDATE users SET user_hash='».$hash.»‘ «.$insip.» WHERE user_id='».$data[‘user_id’].»‘»); // Ставим куки setcookie(«id», $data[‘user_id’], time()+60*60*24*30, «/»); setcookie(«hash», $hash, time()+60*60*24*30, «/», null, null, true); // httponly . // Переадресовываем браузер на страницу проверки нашего скрипта header(«Location: check.php»); exit(); > else < print "Вы ввели неправильный логин/пароль"; >> ?> Логин
Пароль
Не прикреплять к IP (небезопасно)
Логин
Пароль
Не прикреплять к IP(не безопасно)
Для защиты формы логина от перебора, можно использовать капчу или временную задержку на повторную авторизацию.
Автор: http://jiexaspb.habrahabr.ru/. Адаптация под PHP 5.5 и MySQL 5.7 KDG.
Куки с флагом HttpOnly не видны браузерному javascript-коду, а отправляются только на сервер. На практике у вас никогда не будет необходимости получать их содержимое в javascript. А вот злоумышленнику, нашедшему XSS – а XSS так или иначе когда-нибудь где-нибудь найдется – отсутствие HttpOnly на авторизационных куках доставит много радости.
Другие примеры авторизации на PHP:
Регистрация и Авторизация на PHP + MySQL
Доброго времени суток друзья! Давай с Вами рассмотрим регистрацию пользователей на PHP. Для начала давайте определим условия для нашей регистрации пользователей:
Условия для регистрации пользователей
- Пароль шифруем при помощи алгоритма MD5
- Пароль будем «солить»
- Проверка на занятость Логина
- Активация пользователя письмом.
- Запись и хранение данных в СУБД MySQL
Для написание данного скрипта нам нужно понять, что такое регистрация пользователя. Регистрация пользователя – это получения данных реального пользователя, обработка и хранение данных.
Если объяснять простыми словами то регистрация это всего лишь запись и хранение определенных данных по которым мы можем авторизировать пользователя в нашем случае – это Логин и Пароль.
Авторизация — предоставление определённому лицу или группе лиц прав на выполнение определённых действий, а также процесс проверки данных прав при попытке выполнения этих действий. Проше говоря с помощью авторизации мы можем разграничить доступ к тому или иному контенту на нашем сайте.
Рассмотрим структуру каталогов скриптов для реализации нашей регистрации с авторизацией. Нам нужно разбить скрипты на логические составляющие. Модули регистрации и авторизации мы поместив в отдельный каталог. Так же в отдельные каталоги мы поместим подключение к базе данных MySQL, файл с пользовательскими функциями, файл стилей CSS и наш шаблон HTML. Данная структура позволяет быстро ориентироваться в скриптах. Представьте себе, что у Вас большой сайт с кучей модулями и т.д. и если не будет порядка, то будет очень сложно что-то отыскать в таком бардаке.
Так как мы будем хранить все данные в СУБД MySQL, то давайте создадим не большую таблицу в которой будем хранить данные о регистрации.
Для начала нужно создать таблицу в базе данных. Таблицу назовем bez_reg где bez – это префикс таблицы, а reg название таблицы.
Структура таблицы: bez_reg
-- -- Структура таблицы `bez_reg` -- CREATE TABLE IF NOT EXISTS `bez_reg` ( `id` int(11) NOT NULL AUTO_INCREMENT, `login` varchar(200) NOT NULL, `pass` varchar(32) NOT NULL, `salt` varchar(32) NOT NULL, `active_hex` varchar(32) NOT NULL, `status` int(1) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
Теперь создадим основные скрипты для дальнейшей работы.
Файл INDEX.PHP
//Получаем данные с буфера $content = ob_get_contents(); ob_end_clean(); //Подключаем наш шаблон include './html/index.html'; ?>
Файл CONFIG.PHP
//Адрес базы данных define('BEZ_DBSERVER','localhost'); //Логин БД define('BEZ_DBUSER',''); //Пароль БД define('BEZ_DBPASSWORD',''); //БД define('BEZ_DATABASE',''); //Префикс БД define('BEZ_DBPREFIX','bez_'); //Errors define('BEZ_ERROR_CONNECT','Немогу соеденится с БД'); //Errors define('BEZ_NO_DB_SELECT','Данная БД отсутствует на сервере'); //Адрес хоста сайта define('BEZ_HOST','http://'. $_SERVER['HTTP_HOST'] .'/'); //Адрес почты от кого отправляем define('BEZ_MAIL_AUTOR','Регистрация на http://bezramok-tlt.ru '); ?>
Файл 404.HTML
Ошибка 404
На странице произошла ошибка 404
Вернуться
Файл BD.PHP
//Соединение с БД MySQL $db_connect = mysql_connect( BEZ_DBSERVER, BEZ_DBUSER, BEZ_DBPASSWORD ) or die(BEZ_ERROR_CONNECT); define('BEZ_CONNECT', $db_connect); mysql_select_db( BEZ_DATABASE, BEZ_CONNECT )or die(BEZ_NO_DB_SELECT); //Устанавливаем кодировку UTF8 mysql_query ("SET NAMES utf8"); mysql_query ("set character_set_client='utf8'"); mysql_query ("set character_set_results='utf8'"); mysql_query ("set collation_connection='utf8_general_ci'"); ?>
Файл INDEX.HTML
Файл FUNCT.PHP
Давайте приступим к написанию регистрации. Для начала нам нужно будет сделать шаблон формы регистрации, чтобы пользователь смог внести свои данные для обработки. Далее нам нужно будет написать сам обработчик формы, который проверит на корректность введенные данные пользователя. После того как данные успешно проверенны записываем их в нашу базу данных и отправляем письмо пользователю для активации его аккаунта.
Файл REG.PHP
//Выводим сообщение об удачной регистрации if(isset($_GET['status']) and $_GET['status'] == 'ok') echo 'Вы успешно зарегистрировались! Пожалуйста активируйте свой аккаунт!'; //Выводим сообщение об удачной регистрации if(isset($_GET['active']) and $_GET['active'] == 'ok') echo 'Ваш аккаунт на http://bezramok-tlt.ru успешно активирован!'; //Производим активацию аккаунта if(isset($_GET['key'])) < //Проверяем ключ $sql = 'SELECT * FROM `'. BEZ_DBPREFIX .'reg` WHERE `active_hex` = "'. escape_str($_GET['key']) .'"'; $res = mysqlQuery($sql); if(mysql_num_rows($res) == 0) $err[] = 'Ключ активации не верен!'; //Проверяем наличие ошибок и выводим пользователю if(count($err) >0) echo showErrorMessage($err); else < //Получаем адрес пользователя $row = mysql_fetch_assoc($res); $email = $row['login']; //Активируем аккаунт пользователя $sql = 'UPDATE `'. BEZ_DBPREFIX .'reg` SET `status` = 1 WHERE `login` = "'. $email .'"'; $res = mysqlQuery($sql); //Отправляем письмо для активации $title = 'Ваш аккаунт на http://bezramok-tlt.ru успешно активирован'; $message = 'Поздравляю Вас, Ваш аккаунт на http://bezramok-tlt.ru успешно активирован'; sendMessageMail($email, BEZ_MAIL_AUTOR, $title, $message); /*Перенаправляем пользователя на нужную нам страницу*/ header('Location:'. BEZ_HOST .'less/reg/?mode=reg&active=ok'); exit; >> /*Если нажата кнопка на регистрацию, начинаем проверку*/ if(isset($_POST['submit'])) < //Утюжим пришедшие данные if(empty($_POST['email'])) $err[] = 'Поле Email не может быть пустым!'; else < if(!preg_match("/^[a-z0-9_.-]+@([a-z0-9]+\.)+[a-z]$/i", $_POST['email'])) $err[] = 'Не правильно введен E-mail'."\n"; > if(empty($_POST['pass'])) $err[] = 'Поле Пароль не может быть пустым'; if(empty($_POST['pass2'])) $err[] = 'Поле Подтверждения пароля не может быть пустым'; //Проверяем наличие ошибок и выводим пользователю if(count($err) > 0) echo showErrorMessage($err); else < /*Продолжаем проверять введеные данные Проверяем на совподение пароли*/ if($_POST['pass'] != $_POST['pass2']) $err[] = 'Пароли не совподают'; //Проверяем наличие ошибок и выводим пользователю if(count($err) >0) echo showErrorMessage($err); else < /*Проверяем существует ли у нас такой пользователь в БД*/ $sql = 'SELECT `login` FROM `'. BEZ_DBPREFIX .'reg` WHERE `login` = "'. escape_str($_POST['email']) .'"'; $res = mysqlQuery($sql); if(mysql_num_rows($res) >0) $err[] = 'К сожалению Логин: '. $_POST['email'] .' занят!'; //Проверяем наличие ошибок и выводим пользователю if(count($err) > 0) echo showErrorMessage($err); else < //Получаем ХЕШ соли $salt = salt(); //Солим пароль $pass = md5(md5($_POST['pass']).$salt); /*Если все хорошо, пишем данные в базу*/ $sql = 'INSERT INTO `'. BEZ_DBPREFIX .'reg` VALUES( "", "'. escape_str($_POST['email']) .'", "'. $pass .'", "'. $salt .'", "'. md5($salt) .'", 0 )'; $res = mysqlQuery($sql); //Отправляем письмо для активации $url = BEZ_HOST .'less/reg/?mode=reg&key='. md5($salt); $title = 'Регистрация на http://bezramok-tlt.ru'; $message = 'Для активации Вашего акаунта пройдите по ссылке '. $url .''; sendMessageMail($_POST['email'], BEZ_MAIL_AUTOR, $title, $message); //Сбрасываем параметры header('Location:'. BEZ_HOST .'less/reg/?mode=reg&status=ok'); exit; > > > > ?>
Файл REG_FORM.HTML
Регистрация пользователей PHP MySQL с активацией письмом
Поля со значком * обязательны для заполнения
Так как регистрация пользователей у нас готова, самое время написать авторизацию. Создадим форму для авторизации пользователей, далее напишем обработчик формы авторизации и на последок сделаем скрипт show.php который будет показывать нам авторизированны мы в системе или нет.
Файл AUTH.PHP
//Если нажата кнопка то обрабатываем данные if(isset($_POST['submit'])) < if(empty($_POST['email'])) $err[] = 'Не введен Логин'; if(empty($_POST['pass'])) $err[] = 'Не введен Пароль'; //Проверяем наличие ошибок и выводим пользователю if(count($err) >0) echo showErrorMessage($err); else < /*Создаем запрос на выборку из базы данных для проверки подлиности пользователя*/ $sql = 'SELECT * FROM `'. BEZ_DBPREFIX .'reg` WHERE `login` = "'. escape_str($_POST['email']) .'" AND `status` = 1'; $res = mysqlQuery($sql); //Если логин совподает, проверяем пароль if(mysql_num_rows($res) >0) < //Получаем данные из таблицы $row = mysql_fetch_assoc($res); if(md5(md5($_POST['pass']).$row['salt']) == $row['pass']) < $_SESSION['user'] = true; //Сбрасываем параметры header('Location:'. BEZ_HOST .'less/reg/?mode=auth'); exit; >else echo showErrorMessage('Неверный пароль!'); > else echo showErrorMessage('Логин '. $_POST['email'] .' не найден!'); > > ?>
Файл AUTH_FORM.HTML
Введите свой Логин и Пароль для входа!
Файл SHOW.PHP
//Проверяем зашел ли пользователь if($user === false) echo 'Доступ закрыт, Вы не вошли в систему!
'."\n"; if($user === true) echo 'Поздравляю, Вы вошли в систему!
'."\n"; ?>
Автор не несет ответственности за использования данных скриптов у себя на сайте. Вы можете их использовать на свой страх и риск!
Для тех у кого последняя версия PHP выкладываю данный скрипт с использованием PDO т.к. расширение MySQL устарело и было удалено из новой версии PHP. Скачать регистрация и авторизация php mysql pdo
Архив обновлен 24.02.2015г.
Внимание: Если вы используете данный скрипт на локальном сервере типа DENWER, XAMPP, то не стоит ждать писем на свой почтовый ящик. Письма лежат в заглушке sendmail. В Denwer вы их можете найти по пути Z:\tmp\!sendmail\ открыть данные файлы вы сможете в любом почтовом клиенте.