Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
C++. Мастер-класс в задачах и примерах. Авторы: Кузнецов М.В., Симдянов И.В. PHP Puzzles. Авторы: Кузнецов М.В., Симдянов И.В. MySQL на примерах. Авторы: Кузнецов М.В., Симдянов И.В. Социальная инженерия и социальные хакеры. Авторы: Кузнецов М.В., Симдянов И.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум PHP

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Реализация системы "антифлуд" в PHP с использованием MySQL
 
 автор: Inque   (21.05.2007 в 10:45)   письмо автору
 
 

Здраствуйте, я работаю сейчас над созданием блока кода, который должен будет пользователя "сдерживать" при особо активных действиях. Помогите спроектировать эти действия хотя бы с логической части. У меня есть некоторые размышления, но, боюсь, есть намного более простое решение проблемы, о котором я не знаю.

Итак. У меня алгоритм следующий. Создаю табличку `activity` с полями `id` (или `ip`), `name`, `last_activity`, `activity_check`. Представим такую ситуацию. Пользователь вызывает форму для авторизации, набирает там свои идентификационные данные. После отправки формуляра происходит следущее: в таблице `activity` ищется пользователь с данным `ip`, если такового не существует, мы авторизируем пошльзователя, и если авторизация пройдена. создаем запись, куда помещаем эти данные: ip, name, time() и 0 в поле `activity_check`, потому что пользователь авторизируется, а если авторизация не прошла, то создается аналогичная запись без `name`. Если же после отправки формуляра мы находим в `activity` пользователя с данным `ip`, то мы не создаем новой записи, а обновляем текущую. Но сначала мы должны узнать значение поля `activity_checks` и если на данный момент `activity_checks` >= 3 мы проверяем, с момента последней активности прошло 15 минут или нет. Если да - прописываем в `activity_checks` ноль, если нет - блокируем пользователя от любой активности на форуме. Как происходит обновление: мы узнаем, какое у пользователя с `activity_check` и `last_activity`. Если activity_checks менее 3х (else условие для предыдущей развилки), то если (time() - $row->last_activity <= 60), т.е. с момента последней активности прошло менее минуты, то мы увеличиваем значение поля `activity_checks` на единицу, иначе прописываем туда ноль.


Итак, как бы я коряво не объяснил, думаю, хоть кто-то что-то понял. И по сему вопрос, как мне сделать это быстрее, надежнее и проще? З.Ы. эта таблица будет также использоваться для вывода пользователей "на сайте"

   
 
 автор: Trianon   (21.05.2007 в 10:57)   письмо автору
 
   для: Inque   (21.05.2007 в 10:45)
 

Вы же всё достаточно подробно расписали, осталось только алгоритм на php переложить.

Единственный вопрос - Вы вправду считаете, что одновременно с одного IP может прийти не более одного пользователя?

   
 
 автор: Inque   (21.05.2007 в 12:28)   письмо автору
 
   для: Trianon   (21.05.2007 в 10:57)
 

Вы знаете, я долго думал над этим, но пока мне не приходит более умной идентификации пользователя в таблице, нежели по `ip`. Я хотел все делать через `id` пользователя, но подумал о том, что хорошо бы ограничить попытки отправки формы авторизации, дабы защитить форумчан от брута пароля... Я знаю, что с одного ip может сидеть несколько людей, даже десятки, особенно в моем случае (форум для мобильных устройств, у билайна на 1м айпи несколько десятков пользователей), но пока не придумал ничего другого, служащего для данной ситуации primary key'ем :). Если у вас есть мысли по оптимизации данного скриптика, пожалуйста, советуйте, я с PHP только с января.

   
 
 автор: Trianon   (21.05.2007 в 13:06)   письмо автору
 
   для: Inque   (21.05.2007 в 12:28)
 

собственно, три мысли приходят в голову.
1. ставить клиенту Cookie. Тех, кто установку cookies игнорирует - даже не пытаться авторизовывать более чем на один http-запрос.
2. учитывать user-agent
3. блокировать логин, а не ip

   
 
 автор: Inque   (28.05.2007 в 10:43)   письмо автору
 
   для: Trianon   (21.05.2007 в 13:06)
 

По вашему предложению:
1. Так надоели эти куки - жуть, у меня они еще и для идентификации пользователя на форуме служат, я, кстати, тему создавал :)

2. Все будут сидеть с Opera Mini - сайт под мобильники

3. При отправке формы авторизации еще нет логина... А может не прогонять через антифлуд отправку формы регистрации/авторизации, зачем лишний гемор? Но тогда как же брут - подбор пароля...

   
 
 автор: Trianon   (28.05.2007 в 11:07)   письмо автору
 
   для: Inque   (28.05.2007 в 10:43)
 

1. --
2. У Оперы свои поля user-agent есть.
3. Вы сказали, что реализуете антифлуд, а не защиту от повторных регистраций.
Последняя делается строго по капче.

   
 
 автор: Inque   (28.05.2007 в 16:33)   письмо автору
 
   для: Trianon   (28.05.2007 в 11:07)
 

!Конечно! Однако я хотел убить 2х зайцев одним выстрелом! А антифлуд, конечно же, буду по id'шнику реализовывать... Пожалуйста, будьте так добры, объясните, что значит "по капче" и что, у opera mini разные юзер_агенты могут быть? В зависимости от версии что ли?

   
 
 автор: kasmanaft   (28.05.2007 в 17:14)   письмо автору
 
   для: Inque   (28.05.2007 в 16:33)
 

"по капче" - сцылко нумер раз, нумер дыва

> разные юзер_агенты могут быть?
У оперы наверное, тоже могут быть разные, но в любом случае, люди-то к Вам будут ходить не только с оперы. Чуть ли не у каждого телефона свой юзер агент (мне почему-то так кажется, могу ошибаться). Не надо забывать про всякие КПК и т.д.
Так что нужно просто запомнить последний ЮА пользователя.. И вместе с (1)(3) использовать.

   
 
 автор: Inque   (06.06.2007 в 23:19)   письмо автору
 
   для: kasmanaft   (28.05.2007 в 17:14)
 

Понял, спасибо, но вообще-то это несколько ущербно для трафика... Ну буду думать ;)

   
 
 автор: Disable   (07.06.2007 в 00:42)   письмо автору
 
   для: Inque   (06.06.2007 в 23:19)
 

С ип для мобильных устройств есть 2 больших НО:
1. некоторые операторы предоставляют идинаковые ип разным клиентам (бывает что половина города на одном ип)
2. есть операторы, которые меняют ип клиента при КАЖДОМ запросе, например так
208.131.186.18
208.131.186.9
208.131.186.7

С оперой мини на первый взгляд все мудрено, но в итоге она передает реальный ип и юзер агент (хотя агент можно изменить прямо с нее, так что на него вообще полагаться не стоит).

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

   
 
 автор: Inque   (08.06.2007 в 14:51)   письмо автору
 
   для: Disable   (07.06.2007 в 00:42)
 

Да, наверное... Вобщем, я сегодня, надеюсь доделаю эту схему и выложу код сюда :)

   
 
 автор: Inque   (16.06.2007 в 17:21)   письмо автору
 
   для: Inque   (08.06.2007 в 14:51)
 

Да, кстати. Есть тут такая тема искать пользователя в users.php так, чтобы можно было ссылку представить ввиде:

http://somesite.ru/users.php?Inque

а не так

http://somesite.ru/users.php?name=Inque

Как мне это реализовать? Очень интересно, тему не хочу новую создавать :)

   
 
 автор: Trianon   (16.06.2007 в 21:41)   письмо автору
 
   для: Disable   (07.06.2007 в 00:42)
 

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

   
 
 автор: Inque   (17.06.2007 в 00:05)   письмо автору
 
   для: Trianon   (16.06.2007 в 21:41)
 

А по моему последнему вопросу ничего не скажешь? :)

   
 
 автор: Trianon   (17.06.2007 в 02:27)   письмо автору
 
   для: Inque   (17.06.2007 в 00:05)
 

echo $_SERVER['QUERY_STRING'];

[поправлено модератором]

   
 
 автор: Inque   (17.06.2007 в 13:53)   письмо автору
 
   для: Trianon   (17.06.2007 в 02:27)
 

Спасибо. Я потом по этой строке в базе буду искать. Мне надо будет ее обрабатывать вот этим?


function get_safe_string ($some_string) {
      $safe_string = trim($some_string);   // Удаляем пробельные символы
      $safe_string = htmlspecialchars($safe_string, ENT_QUOTES);   // Конвертируем спецсимволы в строке в HTML-представление.
      $safe_string = stripslashes($safe_string);   // Удаляем обратные слеши

      return $safe_string;
}

   
 
 автор: Trianon   (18.06.2007 в 10:59)   письмо автору
 
   для: Inque   (17.06.2007 в 13:53)
 

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

И вроде как комментарии стоят.... Значит Вы знаете, что делаете. Тогда почему опять такой компот?

См. задачу 21. В разделе "задачи".

   
 
 автор: Inque   (20.06.2007 в 18:23)   письмо автору
 
   для: Trianon   (18.06.2007 в 10:59)
 


function get_safe_string ($some_string) { 
      $safe_string = trim($some_string);   // Удаляем пробельные символы 
      $safe_string = stripslashes($safe_string);   // Удаляем обратные слеши 
      $safe_string = htmlspecialchars($safe_string, ENT_QUOTES);   // Конвертируем спецсимволы в строке в HTML-представление. 
      
      return $safe_string; 
}


Так проблема решена? Меня больше волнует то, надо ли эту строку прогонять через данный фильтр - строка будет использована для запросов в БД.

   
 
 автор: cheops   (21.06.2007 в 10:53)   письмо автору
 
   для: Inque   (20.06.2007 в 18:23)
 

Дело в том, что stripslashes() не решает проблему кавычек и нарушения синтаксиса... если вы хотите защититься от SQL-инъекции лучше использовать конструкцию
<?php
  
if (!get_magic_quotes_gpc())
  {
    
$some_string mysql_escape_string($some_string);
  }
?>

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

   
 
 автор: Inque   (21.06.2007 в 12:09)   письмо автору
 
   для: cheops   (21.06.2007 в 10:53)
 


if (!get_magic_quotes_gpc()) {...}

Что проверяет данная конструкция? Впервые такое вижу. И еще, нельзя ли просто этот код впихнуть в мою функцию? Я стремлюсь к тому, чтобы сделать что-то универсальное и не писать определенную последовательность фильтрации каждый раз, когда я загоняю данные в бд или вытаскиваю из нее что-то. Вобщем, я понял, что делаю что-то не так, а по сему прошу, будьте добры, напишите, чем бы вы фильтровали все данные на входе в БД и чем бы на выходе преобразовывали в нормальное представление. Это форум, очень важно, чтобы вероятность дыры в инъекциях и не только сводилась к минимуму.

   
 
 автор: Trianon   (22.06.2007 в 01:40)   письмо автору
 
   для: Inque   (21.06.2007 в 12:09)
 

Вот в этой теме я как-то сделал попытку раскрыть суть метаморфоза строк на пути от формы ввода к браузеру через БД.
Возможно, Вас заинтересует.
http://softtime.ru/forum/read.php?id_forum=3&id_theme=14355

   
 
 автор: cheops   (22.06.2007 в 12:06)   письмо автору
 
   для: Inque   (21.06.2007 в 12:09)
 

Данная конструкция определяет включены или отключены магические кавычки - автоматическое экранирование спец-символов в POST-, GET-, COOKIE- данных - они могут быть включены на сервере, а могут быть отключены. Если включены - экранировать ничего не нужно - об этом заботиться сам сервер, если отключены - нужно. Конструкция get_magic_quotes_gpc() и позволяет добиться универсальности при обработке текстовых значений, которые заключаются в кавычки перед помещением в базу данных. Все числовые значения, которые в кавычки, как правило, не помещаются проверяются либо при помощи спец-функций PHP (например, intval()), либо при помощи регулярных выражений.

PS Вы можете ориентироваться на исходные коды этого форума в разделе downloads (все коды тщательно комментированы на русском языке) - в нём защита от SQL-инъекций вылизана.
PPS Функции stripslashes() вообще не должна использоваться в обработке текста перед помещением в базу данных.

   
 
 автор: Trianon   (24.06.2007 в 03:08)   письмо автору
 
   для: cheops   (22.06.2007 в 12:06)
 

>Если включены - экранировать ничего не нужно - об этом заботиться сам сервер,
Это утверждение как минимум неполное.

Если данные, помещаемые в запрос, взялись не из GET POST COOKIE или REQUEST ,
а из любого другого источника - например,
из загруженного пользователем файла
из файла находящегося на сервере, или полученного по FTP
из сокета, curl , imap и других методов получения чужих данных
и так далее!!!!
=-то экранирование потребуется.

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

Именно поэтому этот кошмар (magic quotes) из php6 выкинут.

   
 
 автор: Osipov   (24.06.2007 в 14:07)   письмо автору
 
   для: Inque   (21.05.2007 в 10:45)
 

Cookeis ничего не дают, я например, кода пишу ботов никогда не держу ненужные Cookies.

А поступал я вот как для антифлуда: у меня есть лимит --- пятьдесят модификационных действий в 15 минут с одного IP и 150 модификаций в 30 минут из одной подсети (храню модификации в таблице MySQL), как только лимит превышен, если это с одного IP, то полностью баню его (при этом если в одной подсети более четырёх забаненных IP --- баниться подсеть, об этом позже), а все действия отменяю (у меня был хороший механизм для отмены модификаций). Затем, когда просматриваю базу забаненых пользователей, смотрю, действительно ли он флудер, если произошла ошибка, то извиняюсь и возвращаю всё обратно.

Когда блокируется подсеть, то из неё запрещаются только модификации, а просмотр разрешается. Кроме того, если юзер --- не флудер, а его подсеть заблокирована, то я выдаю ему доверительный аккаунт (на странице написано "ваша подсеть блокирована, для получения доступа пишите админу") --- то есть аккаунт, с которого он может заходить из заблокированной подсети.

И ещё обязательно забаньте сразу все IP всех проксей, какие сможете найти в интернете.

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

Кроме того на большинство форм я поставил картинку, защищающую от ботов.

   
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования