Поиск на сайте
Главная Журнал Форум Wiki DRKB Страны мира

Защита от DOS-атак в ASP.NET

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

for( int i = 0; i < 100000; i ++ )
{
   WebClient client = new WebClient();
   client.DownloadString("http://www.microsoft.com/default.aspx");
}

Уже после нескольких запросов Вы обнаружите, что в ответ от сервера приходит страница с ошибкой. Однако, это совсем не значит, что сервер уже упал. Просто сайт отверг Ваши последние запросы. Таким образом Вы получили отказ в ообслуживании (Denial of Service или сокращённо DOS).

Самым простым способом защиты от подобного флуда является подсчёт количества запросов с определённого айпишника и запоминание этого значения в кэше ASP.NET. А когда количество запросов превысит допустимый порог, то отвергать запросы с этого адреса в течение определённого срока, например на 10 минут. Через 10 минут вновь начать обрабатывать поступающие запросы с конкретного айпишника.

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

public static class ActionValidator
{
     private const int DURATION = 10; // 10-минутный период
  
     public enum ActionTypeEnum
     {
         FirstVisit = 100, // Самый значимый параметр, подбирать его значение надо осторожно. 
         ReVisit = 1000,  // Повторные посещения особо не ограничиваем
         Postback = 5000,    // Это тем более не проблема
         AddNewWidget = 100, 
         AddNewPage = 100,
     }

Далее рассмотрим статический метод IsValid, который проверяет не достигнуто ли предельное значение по каждому типу запраса. Метод возвращает true, если лимит по запросу не достигнут и false, если запрос пользователя можно отклонить. Если IsValid вернул false, то можно просто вызвать Request.End(), тем самым защитив ASP.NET от дальнейшей загрузки. Так же можно сделать редирект на страницу с сообщением о превышении количества запросов с этого айпи.

public static bool IsValid( ActionTypeEnum actionType )
{
   HttpContext context = HttpContext.Current;
   if( context.Request.Browser.Crawler ) return false;
   
   string key = actionType.ToString() + context.Request.UserHostAddress;
   var hit = (HitInfo)(context.Cache[key] ?? new HitInfo());
     
   if( hit.Hits > (int)actionType ) return false;
   else hit.Hits ++;
    
   if( hit.Hits == 1 )
      context.Cache.Add(key, hit, null, DateTime.Now.AddMinutes(DURATION), 
         System.Web.Caching.Cache.NoSlidingExpiration, 
         System.Web.Caching.CacheItemPriority.Normal, null);
   return true;
}

Ключом в кэше является пара: "типа действия" и IP-адрес клиента. Сначала идёт проверка, есть ли в кэше точно такая же пара. Если нет, то пара добавляется в кэш и начинается отсчёт срока. По истечение срока пара автоматически удалится из кэша и, если пользователь продолжит посещение сайта, то всё повторится сначала. В случае если пара уже присутствует в кэше, то метод проверяет не достигнут ли предел и, если нет превышения, то счётчик увеличивается на еденицу. Принудительно записывать новое значение счётчика в кэш не нужно, так как hit всего лишь ссылается на строку в кэше и обновление счётчика происходит автоматически. Однако если это сделать, то значение экспирации в кэше для данной пары будет обновлено и нарушится логика возобновления отсчёта на конкретный срок.

Использовать этот класс можно прямо на default.aspx:

protected override void OnInit(EventArgs e)
{
   base.OnInit(e);
 
   // Проверяем можно ли обработать повторное посещение
   if( !base.IsPostBack ) 
   {
      // Блокируем запросы без кукисов
      if( Profile.IsFirstVisit )
      {
         if( !ActionValidator.IsValid(ActionValidator.ActionTypeEnum.FirstVisit))  
            Response.End();
      }
      else
      {
         if( !ActionValidator.IsValid(ActionValidator.ActionTypeEnum.ReVisit) )  
            Response.End();
      }
   }
   else
   {
      // Ограничение количества постбэков
      if( !ActionValidator.IsValid(ActionValidator.ActionTypeEnum.Postback) ) 
            Response.End();
   }
}

В этом примере проверяются первый визит, повторный визит, постбэки и т.д.

Конечно, защиту от DoS атак можно переложить на плечи брэндмауэров, таких как Cisco. Любой хостинг-провайдер будет уверять Вас, что вся их сеть защищена от DOS и DDOS (Distributed DOS) атак. Однако, от TCP SYN атак и флуда кривых пакетов они защищаются на аппаратном уровне, в то время как DOS-атаки работают на уровне приложения и, соответственно, защита от них так же должна быть встроена в приложение.

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




Основные разделы сайта


 

Реклама