Пример (теория) безопасной авторизации пользователей и администратора. Вопросы.

Гриша К.

Новичок
Пример (теория) безопасной авторизации пользователей и администратора. Вопросы.

Авторизация пользователей с использованием html формы и сессий (без cookie).
Я сразу хотел бы узнать ваше мнение по поводу использования в качестве имени пользователя не Ник (который досутпен для посетителей), а e-mail пользователя, который ни где не отображается.

Предполагаемый вариант решения задачи:
(1) Пользователь заходит на страницу защищенную паролем, если он не авторизован, то перенаправляю его на страницу авторизации.
(2) На странице авторизации проверяю, только, чтобы все поля были заполнены, дальше выполняю запрос к БД.
(3) Если пользователь 10 раз ввел неверно пароль, то дальше для подтверждения того что авторизоваться пытается человек, а не машина, вывожу человекочитаемую надпись, на которой написан код подтверждения для ввода в форму. И после успешной авторизации, в течение часа всеравно требую вводить код подтверждения с картинки.
Для учета кол-ва попыток аворизации пользователя, каждую неудчаную попытку записываю в специальную таблицу user_danger (username, date, time)
(4) Веду журнал логов, делаю записи при каждой неудачной попытки авторизации - error_log('Логин, Пароль, REMOTE_ADDR, HTTP_X_REAL_IP', http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'], 0). На 11 неверной попытке отправляю сообщение c ошибкой на e-mail - error_log('...', 1, "...@...")

Для авторизация администратора и модераторов использую тот же метод, что и для авториазции обычных пользователей, но после 3-ей неверной попытки блокирую пользователя с такими правами. Учетную запись для администратора и модераторов, создаю в отдельной от обычных пользователей таблицы БД.
ВОПРОСЫ
[1] - Данные вводимые пользователем я обрабатываю так: удаляю лишние пробелы - trim(); прослэшиваю в запросе к БД - mysql_real_escape_string(); пароль шифрую - MD5(). В статье "Приемы безопасного программирования веб-приложений на PHP", в имени пользователя запрещается вводить любые символы, кроме букв русского и латинского алфавита, знака "_" (подчерк), пробела и цифр. Допустимо ли не ограничивать таким образом имя пользователя (логин) при регистрации и соответсвенно авторизации?
[2] - Как лучше осуществлять чистку таблицы (user_danger), в которую записываются все неудачные попытки авторизации? Так как обращаться к этой таблице придется при каждом запросе, то сразу же смотреть, если есть ли записи для данного пользователя сделанные не раньше 1 часа назад и при успешной авторизации такие записи удалять.
[3] - Как защититься от перегрузки сервера (DOS-аттака)? Так как запрос к БД, на проверку кол-ва неверных авторизаци будет осуществляться всегда, то возможно что на страницу авторизации могут сделать к примеру 1000000 обращений, что может повлиять на работо способность сервера. Я предполагаю делать задержку выполнения сценария после 10 неудачной авторизации - sleep(2)
----------------------------------------
Изученный материал:
http://phpclub.ru/detail/article/php_security1 - Безопасность статья 1
http://phpclub.ru/detail/article/php_security2 - Безопасность статья 2
http://phpclub.ru/detail/article/php_security3 - Безопасность статья 3
http://phpclub.ru/detail/article/2003-12-01 - Авторизация
http://phpclub.ru/detail/article/page_password1 - Пароль на страницу статья 1
http://phpclub.ru/detail/article/page_password2 - Пароль на страницу статья 2
http://phpclub.ru/talk/showthread.php?s=&threadid=79299 - Генрация изображений
http://phpclub.ru/talk/showthread.php?s=&threadid=78132 - Подбор пароля
И другое...
 

440hz

php.ru
Гриша К.
я всегда разделяю login/pass и displayname.
к примеру:
login:grisha
displayname: <Гриша К.:->

p.s. админка, да. лежит чисто в /adm/. паранойей не страдаю.

>И очень много сайтов используют для панели администратора раздел /admin/
p.p.s ты удивишься сколько юзают /myphpadmin/ без авторизации. 8)
 

Гриша К.

Новичок
440hz, спасибо за ответ.
Посмотрел вашу админку: после нексокльких неудачных попыток авторизации выскочиал ошибка - увидел данные своего компьютера - интересно. : )
В моем каталоге ссылок, я допускаю и удаляю ссылки, как раз именно с использованием myphpadmin, но мне достаточно менять статус и все. Хорошая безопасность такого метода, Но в больших проектах, в том же интернет-магазине, так не стоит делать - неудобно (больше временнхы затрат), убедился на личном опыте.
 

Andreika

"PHP for nubies" reader
но после 3-ей неверной попытки блокирую пользователя с такими правами
правильно... лучше его вообще удалить нафик

Как защититься от перегрузки сервера... Я предполагаю делать задержку выполнения сценария после 10 неудачной авторизации - sleep(2)
тоже верно... чем быстрее сервер помрет, тем быстрее закончицца атака
 

Гриша К.

Новичок
Andreika, спасибо за ответ.
правильно... лучше его вообще удалить нафик
Решение обосновано тем, что разблокировать пользователя я смогу легко, зайдя к примеру через phpmyadmin и очистев таблицу неудачных авторизаций, а пароль уже невозможно подобрать на 100%. Предложите пожалуйста ваше решение. Возможно можно сделать также как и для ообычных пользователей?

тоже верно... чем быстрее сервер помрет, тем быстрее закончицца ат
Я подозревал что функция sleep(2) может вызывать дополнительные высокие нагрузки на сервер. Предложите пожалуйста ваше решение от перегрозок сервера, если таковое есть.
 

Solid

Drosera anglica
Делай как на registry.eu. У них под это несколько серверов задействовано.
Первый, тот что внешний внешний - отвечает за проверку IP и за количество полученных пакетов от каждого пользователя. Если IP присутствует в базе данных, и если за последние 10 секунд было послано менее 10 пакетов - пропускает к следующему серверу. Следующий сервер, второй, проверяет username и password. Если всё хорошо - пропускает к главному серверу. Главный сервер избавлен от любых DDoS или же несанкционированных попыток доступа к данным.
 

Andreika

"PHP for nubies" reader
Гриша К.
у мну нет решений ) я ж не знаю что за сайт у тебя такой

в качестве имени пользователя не Ник (который досутпен для посетителей), а e-mail пользователя
нуу.. допустим у мну домен свой есть и недостатка в мылах не испытываю... могу при регистрации написать [email protected] ... а вот вспомнить написанное тяжелее
login/displayname использовать для безопасности тоже сомнительно - если он может совпадать с логином он будет совпадать с логином )

Я подозревал что функция sleep(2) может вызывать дополнительные высокие нагрузки на сервер.
sleep(2) не несет дополнительных нагрузок на сервер сама по себе.. просто больше потоков будет висеть в памяти, больше соединений одновременно будет занято... метода интересная если будут подбирать пароль - запрос, 2 сек, разбор полетов, запрос... и все в один поток... но потоков/скриптов будет больше.. а уж dos в один поток не представляю себе
 

Positive

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

kruglov

Новичок
Positive
Ага, а еще можно кластер собрать из 100 серверов, тогда им никакой дос не страшен.

Делать запрет на попытки входа с одного IP в течение минуты. Первые 2-3 (5, 10...) попытки пропускаем, остальные - минуту/две/час говорим login incorrect.

Гриша К.
>разблокировать пользователя я смогу легко
Готовы это делать, скажем, 50 раз в день?

-~{}~ 10.04.06 15:28:

http://xpoint.ru/forums/internet/security/thread/23871.xhtml

-~{}~ 10.04.06 15:30:

> пароль шифрую - MD5().
[m]crypt[/m] посолиднее будет.
 

Positive

Новичок
kruglov
Ну если такой подход серьезный и DoSа бояться то потратить 30 минут на настройку хоста на апаче мне кажется вполне резонным. Иначе вообще проблемы не вижу.
 

kruglov

Новичок
Сергей Тарасов
Ну, не зря ж ее придумали?
Украдет злодей базу как-нибудь и расшифрует пароли хотя бы с помощью публичной базы MD5.
А если там паролики в Blowfish - пущай подбирает.
 

Positive

Новичок
Я кстати тоже crypt обычно использую для хранения паролей :)

$hash = crypt ($pass, $pass);
 

Гриша К.

Новичок
Спасибо большое всем за ответы.

Solid
(1) В данный момент в моем распоряжение 1 сервер с 1ГБ виртуального хостинга. Дальше расчитываю купить и разместить свой web-сервер (collocation).

Andreika
(2) Скорее всего для удобства пользователей стоит использовать displayname в качестве логина и совершенствовать защиту от взлома учетной записи пользователя.
(3) Как я понимаяю DOS атака, это перегрузка сервера, при большем количестве выполнения определенных операция за максимально короткое время (например: запросов к БД). У меня на всех страницах сайта осуществляется вывод данных из БД, и я так понимаю, что каким-то образом, можно через любую такую страницу загрузить сервер. Но когда будет осуществляться подбор пароля, полюбому будет выполняться большое кол-во запросов за короткое время (сколько их за минуту может быть?). Если вывод картинки осуществляет также дополнительную нагрузку на сервер, + при каждой авторизации надо осущесвлять запрос к БД для проверки неудачных попыток авторизации, то я вот и начал думать о какой-то задержке выполнения сценария.

Positive
(4) Как я описал в пункте 1, сейчас я использую виртуальный хостинг и доступа к настройке аппач не имею. Я знаю что при помощи .htcasses можно менять настройки, и хотя на своем комбютере я ставлю Appach+PHP+MySQL, вручную, знаний по поводу описанной вами натсройки я не имею, возможно вы знаете где описаны такие настройки и сможете сообщить мне ссылки эту документацию (на русском).

kruglov
(5) Спасибо за ссылку, со всем ознакомился. Вижу, что соновная проблема с выбором того как блокировать пользователя по IP или по Login.
(6) По поводу того, чтобы делать запрет на попытки входа с одного IP в течение минуты - этот запрет делается проверкой в БД, последнего обращения пользователя, если time < 1 минуты, то неразрешаем авторизацию - и вот я опять думаю о том, что при подборке пароля, может быть за 1 минуту в этом случае выполнять ся большое кол-во запросов, что грозит перегрузкой сервера?
А вообще каким образом несознательный пользователь (негодяй), может узнать страницу для авторизации админа и модератора, если я к примеру сделаю так http://mysite.com/kachipira/zuba30.php, а если он просто введет папку /kachipira/ - то сообщаю об ошибке, что такой страницы не существует - Неполучается ли так, что kachipira-это как логин, а zuba30 - как пароль, т.е. пржде чем попасть на страницу авторизации администратора, пусть попробует подобрать эти логин и пароль.
(7) Кстати по повду использования crypt() вместо MD5(), это интересны вариант, но если могут украсть базы, тогда получается, что доступ к сайту открыт, тут и базы могут удалить вообще, и что угодно - вот этот вараинт мне не ясен всетаки.

По поводу DOS атак я почитал сообщения в этой теме: http://phpclub.ru/talk/showthread.php?postid=465036#post465036 - так понимаю, что скриптами PHP я не обезопашу сервер. Вообще DOS-атка не может повлиять на данные, т.е. к примеру испортить записи в БД, удалить какие-то записи или файлы, получается, что это перегрузит сервер, работать он не будет, пока там память не освободят и т.д. но данные не будут утеряны?
 

kruglov

Новичок
Гриша К.
Насчет kachipira - можно и так. Если, конечно, удобно будет таким образом кучу учетных записей создавать, пароли менять и пр. Потом, адрес страницы у простого пользователя не ассоциируется с чем-от секретным (как пароль) - отошлет он коллеге по аське адрес к админке - и ку.

> при подборке пароля, может быть за 1 минуту в этом случае выполнять ся большое кол-во запросов
Ну, из этой кучи только первые 3-5 реально будут сравниваться с базой, остальные login incorrect и exit()

> тут и базы могут удалить вообще, и что угодно - вот этот вараинт мне не ясен всетаки
Злой хакер украл базу. Вы восстановили из бэкапа, поменяли пароли на sql-server, злой хакер больше не может ничего сделать с базой... Но паролики-то он украл... Пока они зашифрованные - он с ними ничего не сможет сделать.
 

Гриша К.

Новичок
kruglov, спасибо за ответ.
Для обычных пользователей страница с авторизацией будет именть примерно вид: http://site.com/login.php
Для администратора (меня) и для нексольких модераторов (это непросто пользователь, которому как на форуме дали права модератора) выделяется специальнаая страница http://site.com/kachipira/zuba30.php - соответсвенно все будут уведомлены о секретности страницы.
Главное, что вы мне пояснили поэтому поводу, это что такой url нельзя вычислить, невыудив его у кого-то. Спасибо.

Ну, из этой кучи только первые 3-5 реально будут сравниваться с базой, остальные login incorrect и exit()
Немогли бы вы пояснить этот момент, плтому что я не понимаю, почему только первые 3-5 будут сравниваться с базой, а остальные запросы куда денуться.
Я вижу шаблон такой авторизации так:
=> Пользователь вводит логин и пароль,
=> с начала проверяем его в таблице неудачных авторизаций,
=> если у него есть к примеру 3 неудачных попытки, последняя из которых была меньше чем минтуту назад, то выводим сообщение, чтобы к примеру авторизацию пвоторили через минуту.
(Ведь при каждой неудачной попытке, запрос к БД идет всегда, мы же должны проверить что за пользователь делает запрос.
Поясните пожалуйста (может быть на маленьком примере-шаблоне) структуру такой авторизации.)


kruglov, вот поводу того, что злой хакер украл базу, т.е. он не сможет расшифровать пароли пользователей, я так понимаю, свои-то я поменяю, а вот пользователи нет. Но что я непонимаю, если хакер украл базу (как он мог это сдлеать - это мог быть администратор хостинга), ну тогда он ее опять украдет и опять - т.е. если такое произошло, то нужно менять хотсниг и систему безопасности сайта. ВОт этот вопрос я немогу уяснить.

Как пользоваться crypt я разобрался (crypt - Пример 1). Получается при шифровании пароля crypt($password) - результат состоит из 34 символово, т.е. я могу смело делат в БД поле для пароля: `password` varchar(34) NOT NULL,?
 

kruglov

Новичок
Гриша К.
> что такой url нельзя вычислить, невыудив его у кого-то
Кликнет куда-нить, ссылка уйдет в реферер.

> при каждой неудачной попытке, запрос к БД идет всегда
Идет... Ну, если очень прижмет, можно сделать демон, который будет хранить ip-шники в памяти и выдавать "да" или "нет". Но я считаю, что и с MySQL ничего страшного не будет.

> как он мог это сдлеать - это мог быть администратор хостинга
Он воспользовался дыркой (а кто совершенен?), напоил админа, мало ли как. Главное, чтобы мы минимизировали негативные последствия.

>то нужно менять хотсниг и систему безопасности сайта
Поменяли хостинг и систему безопасности. Но не поменяли пароли пользователей. Все щастливы.
 

Гриша К.

Новичок
kruglov, спасибо за разъяснения, теперь я вас понял.

Сейчас решил изменить шифрование всех паролей на crypt().
По примеру с документации crypt, будет необходимо делать 2 запроса к БД, чтобы сравнить пароли: сначала извлекать пароль для пользователя, а потом извлекать пользователя с паролем раынм crypt('Введенный пароль', 'Пароль из первого запроса к БД').

Допустимо ли делать таким образом:
- Записываю пароль в БД: crypt($passwd, $passwd)
- Извлекаю пароль из БД: crypt($input_passwd, $input_passwd)
Вообще при таком варианте получается что пароль будет для определенного слова всегда одного резудьтата, к примеру: MyeFjPJKHmxYQ - т.е. в таком случае уже может быть хакерска база данных паролей, где они шифровались как crypt($passwd, $passwd)?

========================
Делать запрет на попытки входа с одного IP в течение минуты. Первые 2-3 (5, 10...) попытки пропускаем, остальные - минуту/две/час говорим login incorrect.
Я вот думаю, что при таком варианте, возможно что хакер будет подбирать пароль со множества разных ip-адресов (как помойму написано в разделе статьи этого форума), т.е. возможность подбора пароля довольно таки велика.
А если я проверяю пользователя не по IP, а по Login и после 10 попытки вывожу изображение с цифрами - чем плох этот вариант? Что вывод такого изображения, может вызывать большую нагрузку на сервер?
получается, что в любом случае после 10 неверных папыток, нужно вводить цифры с картинки и подбор уже практически невозможен?
 

Andreika

"PHP for nubies" reader
Гриша К.
выделяется специальнаая страница http://site.com/kachipira/zuba30.php - соответсвенно все будут уведомлены о секретности страницы.

помнится >4.5 года назад (фигасе когда это было.. ну в общем тогда еще хотлог появился тока) сделал себе сайтик (и вроде даже по форумам за объяснением каждой функции не лазил.. надо бы глянуть чего там понаделано)... и естественно с гостевухой, в которую даже регулярно писали ) чтобы было можно легко отвечать, редактировать и т.д. нужна была "авторизация". сделана она была примерно так - отдельный файл setpass.php

PHP:
<? if (isset($pass)) { setcookie('mypass',md5($pass); header('/guestbook/'); die; } ?>
<form action=setpass.php><input name=pass><input type=submit></form>

правильность пароля проверялась уже в самой гостевой...
загадка - в чем тут протуп? )

типа ответ - дета через месяца полтора просматривая хотлоговскую статистику обнаружил, что он вполне себе успешно пишет http://site/guestbook/setpass.php?pass=qwerty в "реферы" в общедоступной статистике %) моя статистика правда никому и бесплатно не нужна была, но все равно...
 

Гриша К.

Новичок
Andreika, на указанной мной секретной странице, соотвественно будет форма для авторизации - я просто решил услашнить задачу хакеру, хочет подбирать пароль, так пусть сначала найдеет форму авторизации.

По описанному вами коду, мне непонятно, например каким образом передается $pass и где имя пользователя.

Я кстати вот, что еще придумал, в админке, после 3-попытки, нужно будет ввести код с картинки, но картинка не будет отображаться и только если в строке url ввести какой-то ключ и значение, тогда появится изображение: http://site.com/kachipira/zuba30.php?confirm=image

--------------------------------
Мне сейчас хотелось бы выяснить отрицательные стороны, того метода, что после 10 неверной авторизации (по имени пользователя), выводится изображение, для ввода цифр с картинки.

И для сравнения паролей зашифрованных crypt(), используется 2 запроса к БД?
PHP:
$query1 = mysql_query("select password from users where uername = '$username'");
$password = mysql_reult($query1, 0, 'password')

$query2 = mysql_query("select username from users where username = '$username' and password = '".crypt($password_input, $password)."'")
Дополнительная нагрузка получается?
 
Сверху