Безопасный метод авторизации на PHP

Безопасный метод авторизации на PHP

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

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. Практика -- <br> -- Структура таблицы `users` <br> -- <br> CREATE TABLE `users` ( <br> `user_id` int(11) unsigned NOT NULL auto_increment, <br> `user_login` varchar(30) NOT NULL, <br> `user_password` varchar(32) NOT NULL, <br> `user_hash` varchar(32) NOT NULL, <br> `user_ip` int(10) unsigned NOT NULL default '0', <br> PRIMARY KEY (`user_id`) <br> ) ENGINE=MyISAM DEFAULT CHARSET=cp1251 AUTO_INCREMENT=1 ; <br>

// Страница регситрации нового пользователя

# Соединямся с БД

mysql_connect ( "localhost" , "myhost" , "myhost" );

if(isset( $_POST [ 'submit' ]))

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();

print "<b>При регистрации произошли следующие ошибки:</b><br>" ;

foreach( $err AS $error )

print $error . "<br>" ;

Логин <input name="login" type="text"><br>

Пароль <input name="password" type="password"><br>

<input name="submit" type="submit" value="Зарегистрироваться">

# Функция для генерации случайной строки

function generateCode ( $length = 6 )

<br>

Пароль <input name="password" type="password"><br>

Не прикреплять к IP(не безопасно) <input type="checkbox" name="not_attach_ip"><br>

<input name="submit" type="submit" value="Войти">

# Соединямся с БД

mysql_connect ( "localhost" , "myhost" , "myhost" );

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' ])<br> 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 "Хм, что-то не получилось" ;

print "Привет, " . $userdata [ 'user_login' ]. ". Всё работает!" ;

print "Включите куки" ;

Для защиты формы логина от перебора, можно использовать <a href=«captcha.ru target=»_blank">капчу.

Хочу отметить, что здесь я рассматривал авторизацию основоную на cookies, не стоит в комментариях кричать, что сессии лучше/удобнее и т.д. Спасибо.

📎📎📎📎📎📎📎📎📎📎