Вверх

Блог
RSS лента

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

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

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

1. Модель (клиент)

Регистрация
- логин (a-z0-9)
- пароль
Вход
- логин
- пароль
Cookie
- уникальный идентификатор юзера
- хэш

Модель (сервер) MySQL

Таблица users

  1. user_id (int(11))
  2. user_login (Varchar(30))
  3. user_password (varchar(32))
  4. user_hash (varchar(32))
  5. user_ip (int(10)) по умолчанию 0

При регистрации в базу данных записывается логин пользователя и пароль(в двойном md5 шифровании)
При авторизация, сравнивается логин и пароль, если они верны, то генерируется случайная строка, которая хешируеться и добавляется в БД в строку user_hash. Также записывается IP адрес пользователя(но это у нас будет опциональным, так как кто-то сидит через Proxy, а у кого-то IP динамический... тут уже пользователь сам будет выбирать безопасность или удобство). В куки пользователя мы записываем его уникальный индетификатор и сгенерированный hash.
Почему надо хранить в куках хеш случайно сгенерированной строки, а не хеш пароля?

Почему надо хранить в куках хеш случайно сгенерированной строки, а не хеш пароля?

1. Из-за невнимательности программиста, во всей системе могут быть дырки, воспользовавшийся этими дырками, злоумышленник может вытащить хеш пароля из БД и подставить его в свои куки, тем самым получить доступ к закрытым данным. В нашем же случае, двойной хеш пароля не чем не сможет помочь хакеру, так как расшифровать он его не сможет(теоретически это возможно, но на это он потратит не один месяц, а может быть и год) а воспользоваться этим хешем ему негде, ведь у нас при авторизации свой уникальный хеш прикрепленный к IP пользователя.
2. Если злоумышленник вытащит трояном у пользователя уникальный хеш, воспользоваться им он также не сможет(разве если только, пользователь решил пренебречь своей безопасностью и выключил привязку к IP при авторизации).

2. Практика

  1. — Структура таблицы `users`
  2. CREATE TABLE `users` (
  3. `user_id` int(11) unsigned NOT NULL auto_increment,
  4. `user_login` varchar(30) NOT NULL,
  5. `user_password` varchar(32) NOT NULL,
  6. `user_hash` varchar(32) NOT NULL,
  7. `user_ip` int(10) unsigned NOT NULL default '0',
  8. PRIMARY KEY (`user_id`)
  9. ) ENGINE=InnoDB DEFAULT CHARSET=cp1251 AUTO_INCREMENT=1 ;

register.php

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

  1. # Соединямся с БД
  2. mysql_connect("localhost", "myhost", "myhost");
  3. mysql_select_db("testtable");
  4.  
  5.  
  6. if(isset($_POST['submit']))
  7. {
  8. $err = array();
  9.  
  10. # проверям логин
  11. if(!preg_match("/^[a-zA-Z0-9]+$/",$_POST['login']))
  12. {
  13. $err[] = "Логин может состоять только из букв английского алфавита и цифр";
  14. }
  15.  
  16. if(strlen($_POST['login']) < 3 or strlen($_POST['login']) > 30)
  17. {
  18. $err[] = "Логин должен быть не меньше 3-х символов и не больше 30";
  19. }
  20.  
  21. # проверяем, не существует ли пользователя с таким именем
  22. $query = mysql_query("SELECT COUNT(user_id) FROM users WHERE user_login='".mysql_real_escape_string($_POST['login'])."'");
  23. if(mysql_result($query, 0) > 0)
  24. {
  25. $err[] = "Пользователь с таким логином уже существует в базе данных";
  26. }
  27.  
  28. # Если нет ошибок, то добавляем в БД нового пользователя
  29. if(count($err) == 0)
  30. {
  31.  
  32. $login = $_POST['login'];
  33.  
  34. # Убераем лишние пробелы и делаем двойное шифрование
  35. $password = md5(md5(trim($_POST['password'])));
  36.  
  37. mysql_query("INSERT INTO users SET user_login='".$login."', user_password='".$password."'");
  38. header("Location: login.php"); exit();
  39. }
  40. else
  41. {
  42. print "При регистрации произошли следующие ошибки:
  43. ";
  44. foreach($err AS $error)
  45. {
  46. print $error."
  47. ";
  48. }
  49. }
  50. }

login.php

// Страница авторизации

  1. # Функция для генерации случайной строки
  2. function generateCode($length=6) {
  3. $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHI JKLMNOPRQSTUVWXYZ0123456789";
  4. $code = "";
  5. $clen = strlen($chars) - 1;
  6. while (strlen($code) < $length) {
  7. $code .= $chars[mt_rand(0,$clen)];
  8. }
  9. return $code;
  10. }
  11.  
  12.  
  13. # Соединямся с БД
  14. mysql_connect("localhost", "myhost", "myhost");
  15. mysql_select_db("testtable");
  16.  
  17. if(isset($_POST['submit']))
  18. {
  19. # Вытаскиваем из БД запись, у которой логин равняеться введенному
  20. $query = mysql_query("SELECT user_id, user_password FROM users WHERE user_login='".mysql_real_escape_string($_POST['login'])."' LIMIT 1");
  21. $data = mysql_fetch_assoc($query);
  22.  
  23. # Сравниваем пароли
  24. if($data['user_password'] === md5(md5($_POST['password'])))
  25. {
  26. # Генерируем случайное число и шифруем его
  27. $hash = md5(generateCode(10));
  28.  
  29. if(!@$_POST['not_attach_ip'])
  30. {
  31. # Если пользователя выбрал привязку к IP
  32. # Переводим IP в строку
  33. $insip = ", user_ip=INET_ATON('".$_SERVER['REMOTE_ADDR']."')";
  34. }
  35.  
  36. # Записываем в БД новый хеш авторизации и IP
  37. mysql_query("UPDATE users SET user_hash='".$hash."' ".$insip." WHERE user_id='".$data['user_id']."'");
  38.  
  39. # Ставим куки
  40. setcookie("id", $data['user_id'], time()+60*60*24*30);
  41. setcookie("hash", $hash, time()+60*60*24*30);
  42.  
  43. # Переадресовываем браузер на страницу проверки нашего скрипта
  44. header("Location: check.php"); exit();
  45. }
  46. else
  47. {
  48. print "Вы ввели неправильный логин/пароль";
  49. }
  50. }

check.php

// Скрипт проверки

  1. mysql_connect("localhost", "myhost", "myhost");
  2. mysql_select_db("testtable");
  3.  
  4. if (isset($_COOKIE['id']) and isset($_COOKIE['hash']))
  5. {
  6. $query = mysql_query("SELECT *,INET_NTOA(user_ip) FROM users WHERE user_id = '".intval($_COOKIE['id'])."' LIMIT 1");
  7. $userdata = mysql_fetch_assoc($query);
  8.  
  9. if(($userdata['user_hash'] !== $_COOKIE['hash']) or ($userdata['user_id'] !== $_COOKIE['id'])
  10. or (($userdata['user_ip'] !== $_SERVER['REMOTE_ADDR']) and ($userdata['user_ip'] !== "0")))
  11. {
  12. setcookie("id", "", time() - 3600*24*30*12, "/");
  13. setcookie("hash", "", time() - 3600*24*30*12, "/");
  14. print "Хм, что-то не получилось";
  15. }
  16. else
  17. {
  18. print "Привет, ".$userdata['user_login'].". Всё работает!";
  19. }
  20. }
  21. else
  22. {
  23. print "Включите куки";
  24. }

Ваша оценка: Пусто Средняя: 3.5 (6 votes)

Ответить

 
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Строки и параграфы переносятся автоматически.
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>. Beside the tag style "<foo>" it is also possible to use "[foo]".
  • Image links with 'rel="lightbox"' in the <a> tag will appear in a Lightbox when clicked on.
  • Image links from G2 are formatted for use with Lightbox2
  • Image links with 'rel="lightshow"' in the <a> tag will appear in a Lightbox slideshow when clicked on.
  • Links to HTML content with 'rel="lightframe"' in the <a> tag will appear in a Lightbox when clicked on.
  • Links to video content with 'rel="lightvideo"' in the <a> tag will appear in a Lightbox when clicked on.
  • Links to inline or modal content with 'rel="lightmodal"' in the <a> tag will appear in a Lightbox when clicked on.

Подробнее о форматировании

Главная | Портфолио | Услуги | Контакты | Блог