Давайте посмотрим вокруг: форумы, интернет магазины, гостевые книги и т.д. используют регистрацию и последующую авторизацию пользователей. Можно даже сказать, что это почти необходимая функция каждого сайта (только если это не домашняя страничка Васи Пупкина или не визитная карточка, какой-нибудь небольшой компании). Сегодня я хочу поделиться со всеми новичками информацией, о том, как лучше это все реализовать.
1. Модель (клиент)
Регистрация
- логин (a-z0-9)
- пароль
Вход
- логин
- пароль
Cookie
- уникальный идентификатор юзера
- хэш
Модель (сервер) 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.
Почему надо хранить в куках хеш случайно сгенерированной строки, а не хеш пароля?
Почему надо хранить в куках хеш случайно сгенерированной строки, а не хеш пароля?
1. Из-за невнимательности программиста, во всей системе могут быть дырки, воспользовавшийся этими дырками, злоумышленник может вытащить хеш пароля из БД и подставить его в свои куки, тем самым получить доступ к закрытым данным. В нашем же случае, двойной хеш пароля не чем не сможет помочь хакеру, так как расшифровать он его не сможет(теоретически это возможно, но на это он потратит не один месяц, а может быть и год) а воспользоваться этим хешем ему негде, ведь у нас при авторизации свой уникальный хеш прикрепленный к IP пользователя.
2. Если злоумышленник вытащит трояном у пользователя уникальный хеш, воспользоваться им он также не сможет(разве если только, пользователь решил пренебречь своей безопасностью и выключил привязку к IP при авторизации).
2. Практика
-
— Структура таблицы `users`
-
—
-
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,
-
`user_ip` int(10) unsigned NOT NULL default '0',
-
PRIMARY KEY (`user_id`)
-
) ENGINE=InnoDB DEFAULT CHARSET=cp1251 AUTO_INCREMENT=1 ;
register.php
// Страница регистрации нового пользователя
-
# Соединямся с БД
-
mysql_connect("localhost", "myhost", "myhost");
-
mysql_select_db("testtable");
-
-
-
if(isset($_POST['submit']))
-
{
-
$err = array();
-
-
# проверям логин
-
if(!preg_match("/^[a-zA-Z0-9]+$/",$_POST['login']))
-
{
-
$err[] = "Логин может состоять только из букв английского алфавита и цифр";
-
}
-
-
if(strlen($_POST['login']) < 3 or strlen($_POST['login']) > 30)
-
{
-
$err[] = "Логин должен быть не меньше 3-х символов и не больше 30";
-
}
-
-
# проверяем, не существует ли пользователя с таким именем
-
$query = mysql_query("SELECT COUNT(user_id) FROM users WHERE user_login='".mysql_real_escape_string($_POST['login'])."'");
-
if(mysql_result($query, 0) > 0)
-
{
-
$err[] = "Пользователь с таким логином уже существует в базе данных";
-
}
-
-
# Если нет ошибок, то добавляем в БД нового пользователя
-
if(count($err) == 0)
-
{
-
-
$login = $_POST['login'];
-
-
# Убераем лишние пробелы и делаем двойное шифрование
-
$password = md5(md5(trim($_POST['password'])));
-
-
mysql_query("INSERT INTO users SET user_login='".$login."', user_password='".$password."'");
-
header("Location: login.php"); exit();
-
}
-
else
-
{
-
print "При регистрации произошли следующие ошибки:
-
";
-
foreach($err AS $error)
-
{
-
print $error."
-
";
-
}
-
}
-
}
login.php
// Страница авторизации
-
# Функция для генерации случайной строки
-
function generateCode($length=6) {
-
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHI JKLMNOPRQSTUVWXYZ0123456789";
-
$code = "";
-
$clen = strlen($chars) - 1;
-
while (strlen($code) < $length) {
-
$code .= $chars[mt_rand(0,$clen)];
-
}
-
return $code;
-
}
-
-
-
# Соединямся с БД
-
mysql_connect("localhost", "myhost", "myhost");
-
mysql_select_db("testtable");
-
-
if(isset($_POST['submit']))
-
{
-
# Вытаскиваем из БД запись, у которой логин равняеться введенному
-
$query = mysql_query("SELECT user_id, user_password FROM users WHERE user_login='".mysql_real_escape_string($_POST['login'])."' LIMIT 1");
-
$data = mysql_fetch_assoc($query);
-
-
# Сравниваем пароли
-
if($data['user_password'] === md5(md5($_POST['password'])))
-
{
-
# Генерируем случайное число и шифруем его
-
$hash = md5(generateCode(10));
-
-
if(!@$_POST['not_attach_ip'])
-
{
-
# Если пользователя выбрал привязку к IP
-
# Переводим IP в строку
-
$insip = ", user_ip=INET_ATON('".$_SERVER['REMOTE_ADDR']."')";
-
}
-
-
# Записываем в БД новый хеш авторизации и IP
-
mysql_query("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);
-
-
# Переадресовываем браузер на страницу проверки нашего скрипта
-
header("Location: check.php"); exit();
-
}
-
else
-
{
-
print "Вы ввели неправильный логин/пароль";
-
}
-
}
check.php
// Скрипт проверки
-
mysql_connect("localhost", "myhost", "myhost");
-
mysql_select_db("testtable");
-
-
if (isset($_COOKIE['id']) and isset($_COOKIE['hash']))
-
{
-
$query = mysql_query("SELECT *,INET_NTOA(user_ip) FROM users WHERE user_id = '".intval($_COOKIE['id'])."' LIMIT 1");
-
$userdata = mysql_fetch_assoc($query);
-
-
if(($userdata['user_hash'] !== $_COOKIE['hash']) or ($userdata['user_id'] !== $_COOKIE['id'])
-
or (($userdata['user_ip'] !== $_SERVER['REMOTE_ADDR']) and ($userdata['user_ip'] !== "0")))
-
{
-
setcookie("id", "", time() - 3600*24*30*12, "/");
-
setcookie("hash", "", time() - 3600*24*30*12, "/");
-
print "Хм, что-то не получилось";
-
}
-
else
-
{
-
print "Привет, ".$userdata['user_login'].". Всё работает!";
-
}
-
}
-
else
-
{
-
print "Включите куки";
-
}