А это клавиатура, с помощью которой я творю...
http://kurepin.ru/php/zametki/flood/
Rambler's Top100
PHP. Борьба с примитивным flood-ом

Некоторое время назад передо мной встала проблема безопасности несколько острее, чем стояла до сих пор. Дело в том, что мне пришлось программировать проект, который уже много лет было модно взламывать. "Ко01}{ацкеров" развелось достаточно много и они беспрестанно думают, что бы такого сделать плохого. Путей насолить обычно бывает огромное множество, программисту практически не реально поставить стопроцентно надежный заслон на каждом из них. Но к этому нужно стремиться. Я хочу обсудить пока один из аспектов защиты. Речь пойдет о защите от flood-атак, от одной из их разновидностей.

Flood - это атака, при которой атакующий заваливает сервер частыми запросами.

Разновидностей таких атак существует огромное множество, бывают атаки на уровне TCP/IP, бывают на уровне прикладных протоколов типа HTTP, FTP и т.п. Бывают атаки распределенные, когда атака производится с множества адресов, с такими атаками очень сложно бороться; бывали случаи, когда такими атаками доводили до банкротства вполне серьезных и крупных провайдеров.

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

Поясню на примере гостевой книги. В каждой гостевой книге есть форма для постинга сообщений. Обычно безопасности гостевых книг уделяется не слишком много внимания. Между тем зловредный хацкер может навредить и здесь. Например, можно за несколько секунд организовать автоматический поток бессмысленных сообщений в гостевую книгу.

Чем это грозит? Например, может кончиться выделенное пространство на диске, вебсервер может начать использовать слишком много процессорных ресурсов, за что провайдер может отключить хостинг, ну и на конец, после этого гостевая будет не слишком красиво выглядеть.

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

Вот передо мной и встала проблема защититься от такой ситуации. Ниже приведенный текст php-скрипта содержит функцию, которая призвана помочь побороть данную проблему.

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

// проверка на превышение частоты обращения к скрипту с одного IP-адреса
// (c) Oleg V. Konstantinov 2003.
// syntax: $res = freq_limit($filename,$ip,$interval,$limit);
// $filename   имя файла для хранения
// $ip         адрес текущего запроса
// $interval   интервал ограничения
// $limit      максимальное кол-во обращений за интервал
// $res        кол-во запросов, если есть превышение частоты, иначе 0;

function freq_limit($filename,$ip,$interval,$limit){
  $lip = ip2long($ip);
  
  $tmp = array();         // массив для временного хранения 
  $requests = 1;          // счетчик запросов с данного IP в течении интервала, 
                          // 1 - учитываем текущий запрос

  //читаем файл, открывая его для последующей записи
  $in = fopen($filename,"r+");

  if($in){
    flock($in,LOCK_EX ) or die("Cannot flock file.");
    $now = time();
    while($block = fread($in,8)){
      //каждая запись - ip,time в двоичном формате
      $arr = unpack("Lip/Ltime",$block);
      //если обращение прокисло(прошло время больше интервала) игнорируем
      if( ($now - $arr['time']) > $interval ){
        continue;
      }
      // если в течении интервала был запрос с текущего IP, увеличиваем счетчик
      if($arr['ip'] == $lip){
        $requests++;
      }

      $tmp[] = $arr;
    }
    //обнуляем файл, для последующей записи
    fseek($in,0);
    ftruncate($in,0);
  }else{ //если нет файла, создаем его
    $in = fopen($filename,"w");
    flock($in,LOCK_EX ) or die("Cannot flock file.");
  }
  //заливаем массив
  for($i=0;$i < count($tmp);$i++){
    fwrite($in,pack('LL',$tmp[$i]['ip'],$tmp[$i]['time']));
  }
  //записываем текущий запрос
  fwrite($in,pack('LL',$lip,$now));
  // закрываем файл, блокировка снимается автоматически
  fclose($in);
  // если лимит превышен возвращаем кол-во обращений, иначе 0
  return ($reqs > $limit)?$reqs:0;
}


// Собственно скрипт. Разрешает выполнять с одного IP-адреса до 5 запросов 
// в минуту. 
if(freq_limit("freq-req.bin", getenv("REMOTE_ADDR"),60,5)){
  echo "Абламайтес!";
  exit;
}

echo "Усе пучком!";
Материал подготовил
Олег Константинов
16.02.03

[шаг назад] [печатать] [в начало сайта]



copyright ©2000-2017 Ruslan Kurepin