Как стать автором
Обновить

Тематические Медиа: задача для собеседования

Время на прочтение3 мин
Количество просмотров2.3K
В свете того, что в последнее время похожая тема довольно часто стала появляться на страницах проекта, опубликую задание, которое на протяжении значительного времени мы предлагали соискателям на позицию php-разработчика в нашей компании.



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

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

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

Прилагаю решение, которое сам написал уже после появления задачи, в тот момент, когда особенно «приспичило». Решение довольно простое и грубое, но при этом эффективное (80 мегебайт журнала за 20 секунд). Именно этот скрипт помог защитить один из проектов от одной из атак, когда на сервер ломилось 1500 бездельников.

Со временем стало понятно, что при атаке правильнее оценивать сам трафик (более досканальный и трудозатратный подход, кто чаще с этим сталкивался — так и поступает): содержимое пакетов, заголовки, но, тем не менее, опыт показал, что решение этой задачи однозначно даёт представление о уровне специалиста, утверждающего, что он опытный разработчик и «собаку съел» в области web-программирования.

На решение давалось от часа, до двух времени (в зависимости от хода мысли человека), последний раз она была решена за 1 час 20 минут. Всего решили задачу примерно 10% соискателей.

Теперь у нас будет другая задача.

Исходный код: может читать журнал потоково или из файла, при необходимости добавляет блокирующие правила в брандмауэр. Отказ от регулярных выражений даёт существенный прирост в производительности. Испытывался на файлах размером до 500 мегабайт.

Конечно, всё это можно было написать немного короче и красивее на перле, но хотелось составить некий образец решения задачи именно на php.

#!/usr/local/bin/php
<?php
  if(!empty($argv[1])) $fname = $argv[1]; else $fname = 'access.log';
  $fh = fopen($fname, 'r');
  #$fh = fopen('php://stdin', 'r');
  $timeLimit = 1;
  $countLimit = 50;
  $status = array();

  while ($string = fgets($fh)) {
       $ip = substr($string, 0, strpos($string, ' '));

       if(!empty($status[$ip]['blocked'])) continue;

       $st = strpos($string, '[') + 1;
       $time = strtotime(substr($string, $st, strpos($string, ']', $st + 1) - $st));

       $st = strpos($string, '"') + 1;
       $req = substr($string, $st, strpos($string, '"', $st + 1) - $st);
       $st = strpos($req, " ") + 1;
       $doc = substr($req, $st, strpos($req, " ", $st) - $st);

       $dot = strrpos($doc, ".");
       $dot = $dot ? strlen($doc) - $dot : 0;
       if(!$dot || $dot > 5) {
          if(!empty($status[$ip])) $status[$ip] = array('count'=>0);
          if(!empty($status[$ip]['time']) && $time - $status[$ip]['time'] <= $timeLimit) {
              $status[$ip]['count'] ++;
              if($status[$ip]['count'] >= $countLimit) {
                  echo "$ip : $doc\n";
		  #system ("ipfw table 1 add $ip");
		  #echo "$ip\n";
                  $status[$ip]['blocked'] = 1;
              }
          }

          $status[$ip]['time'] = $time;
          $status[$ip]['doc'] = $doc;
       }
  }
?>
Теги:
Хабы:
Всего голосов 49: ↑36 и ↓13+23
Комментарии144

Публикации

Истории

Ближайшие события

One day offer от ВСК
Дата16 – 17 мая
Время09:00 – 18:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн
Антиконференция X5 Future Night
Дата30 мая
Время11:00 – 23:00
Место
Онлайн
Конференция «IT IS CONF 2024»
Дата20 июня
Время09:00 – 19:00
Место
Екатеринбург
Summer Merge
Дата28 – 30 июня
Время11:00
Место
Ульяновская область