Prevent Denial of Service (DOS) attacks in your web application

Web services are the most attractive target for hackers because even a pre-school hacker can bring down a server by repeatedly calling a web service which does expensive work. Ajax Start Pages like Pageflakes are the best target for such DOS attack because if you just visit the homepage repeatedly without preserving cookie, every hit is producing a brand new user, new page setup, new widgets and what not. The first visit experience is the most expensive one. Nonetheless, it’s the easiest one to exploit and bring down the site. You can try this yourself. Just write a simple code like this:

   1: for( int i = 0; i < 100000; i ++ )
   2: {
   3:    WebClient client = new WebClient();
   4:    client.DownloadString("http://www.pageflakes.com/default.aspx");
   5: }

In your great surprise, you will notice that, after a couple of call, you don't get valid response. It’s not that you have succeeded in bringing down the server. It’s that your requests are being rejected. You are happy that you no longer get any service, thus you achieve Denial of Service (for yourself). I am happy to Deny You of Service (DYOS).

The trick I have in my sleeve is an inexpensive way to remember how many requests are coming from a particular IP. When the number of request exceeds the threshold, deny further request for some duartion. The idea is to remember caller’s IP in Asp.net Cache and maintain a count of request per IP. When the count exceeds a predefined limit, reject further request for some specific duration like 10 mins. After 10 mins, again allow requests from that IP.

I have a class named ActionValidator which maintains a count of specific actions like First Visit, Revisit, Asynchrnous postbacks, Add New widget, Add New Page etc. It checks whether the count for such specific action for a specific IP exceeds the threshold value or not.

   1: public static class ActionValidator
   2: {
3: private const int DURATION = 10; // 10 min period
   4:  
   5:     public enum ActionTypeEnum
   6:     {
   7:         FirstVisit = 100, // The most expensive one, choose the valu wisely. 
   8:         ReVisit = 1000, // Welcome to revisit as many times as use likes
   9:         Postback = 5000,   // Not must of a problem for us
  10:         AddNewWidget = 100, 
  11:         AddNewPage = 100,
  12:     }

The enumeration contains the type of actions to check for and their threshold value for a specific duration – 10 mins.

A static method named IsValid does the check. It returns true if the request limit is not passed, false if the request needs to be denied. Once you get false, you can call Request.End() and prevent Asp.net from proceeding further. You can also switch to a page which shows “Congratulations! You have succeeded in Denial of Service Attack.”

 

   1: 
public static bool IsValid( ActionTypeEnum actionType )
   2: {
   3: HttpContext context  = HttpContext.Current;
   4: 
if( context.Request.Browser.Crawler ) return false;
   5:  
   6: string key = actionType.ToString()  + context.Request.UserHostAddress;
   7:  
   8: HitInfo hit  = (HitInfo)(context.Cache[key] ?? new HitInfo());
   9:  
  10: if( hit.Hits > (int)actionType ) return false;
  11: else hit.Hits ++;
  12:  
  13: if( hit.Hits == 1 )
  14:     context.Cache.Add(key, hit, null, DateTime.Now.AddMinutes(DURATION), 
  15:       System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, null);
  16:  
  17: return true;
  18: }

The cache key is built with a combination of action type and client IP address. First it checks if there’s any entry for the action and the client IP in Cache or not. If not, start the count and store remember the count for the IP in cache for the specific duration. The absolute expiration on cache item ensures after the duration, the cache item will be cleared and the count will restart. When there’s already an entry in the cache, get the last hit count, and check if the limit is exceeded or not. If not exceeded, increase the counter. There is no need to store the updated value in the cache again by doing: Cache[url]=hit; because the hit object is by reference and changing it means it gets changed in the cache as well. In fact, if you do put it again in the cache, the cache expiration counter will restart and fail the logic of restarting count after specific duration.

The usage is very simple:

   1: 
protected override void OnInit(EventArgs e)
   2: {
   3:   base.OnInit(e);
   4:  
   5:   // Check if revisit is valid or not
   6:   if(  !base.IsPostBack ) 
   7:   {
   8:     // Block cookie less visit attempts
   9:     if( Profile.IsFirstVisit )
  10:     {
  11:        if( !ActionValidator.IsValid(ActionValidator.ActionTypeEnum.FirstVisit) Response.End();
  12:     }
  13:    else
  14:     {
  15:      if( !ActionValidator.IsValid(ActionValidator.ActionTypeEnum.ReVisit) ) Response.End();
  16:     }
  17:   }
  18:  else
  19:   {
  20:    // Limit number of postbacks
  21:     if( !ActionValidator.IsValid(ActionValidator.ActionTypeEnum.Postback)  Response.End();
  22:   }
  23: }

Here I am checking specific scenario like First Visit, re-visit, postbacks etc.

Of course you can put in some Cisco firewall and prevent DOS attack. You will get guaranty from your hosting provider that their entire network is immune to DOS and DDOS (Distributed DOS) attacks. What they guaranty is network level attack like TCP SYN attacks or malformed packet floods etc. There is no way they can analyze the packet and find out a particular IP is trying to load the site too many times without supporting cookie or trying to add too many widgets. These are called application level DOS attack which hardware cannot prevent. It must be implemented in your own code.

There are very few websites out their which take such precaution for application level DOS attacks. Thus it’s quite easy to make servers go mad by writing a simple loop and hitting expensive pages or web services continuously from your home broadband connection. I hope this small but effective class will help you implement DOS attack in your own web applications.

 

Update

Here's the code of the full ActionValidator class:

// Copyright (c) Omar AL Zabir. All rights reserved.
// For continued development and updates, visit http://msmvps.com/omar

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

/// <summary>
/// Summary description for ActionValidator
/// </summary>
namespace Dropthings.Web.Util
{
  public static class ActionValidator
  {
  private const int DURATION = 10; // 10 min period
   
  /*
  * Type of actions and their maximum value per period
  *
  */
  public enum ActionTypeEnum
  {
  None = 0,
  FirstVisit = 100, // The most expensive one, choose the value wisely.
  Revisit = 1000, // Welcome to revisit as many times as user likes
  Postback = 5000, // Not must of a problem for us
  AddNewWidget = 100,
  AddNewPage = 100,
  }

  private class HitInfo
  {
  public int Hits;
  private DateTime _ExpiresAt = DateTime.Now.AddMinutes(DURATION);
  public DateTime ExpiresAt { get { return _ExpiresAt; } set { _ExpiresAt = value; } }
  }

  public static bool IsValid( ActionTypeEnum actionType )
  {
  HttpContext context = HttpContext.Current;
  if( context.Request.Browser.Crawler ) return false;

  string key = actionType.ToString() + context.Request.UserHostAddress;

  HitInfo 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;
  }
  }
}

 

Published Sat, Mar 24 2007 14:37 by omar
Filed under:

Comments

# re: Prevent Denial of Service (DOS) attacks in your web application

Saturday, March 24, 2007 6:36 PM by Samiha Esha

Its really very helpful class. Thank you :)

# re: Prevent Denial of Service (DOS) attacks in your web application

Sunday, March 25, 2007 1:21 AM by Russell

A M$ psychophant talks about DDoS! Joke of the millennium!

# re: Prevent Denial of Service (DOS) attacks in your web application

Sunday, March 25, 2007 1:49 AM by omar

Linux psychopath, welcome to my blog :)

I am curious to know how linux protects you from App Level DOS attack. Can you enlighten us with your superior wisdom?

# re: Prevent Denial of Service (DOS) attacks in your web application

Sunday, March 25, 2007 5:19 AM by I Satya Sekhar

Hi

Ur artical is good. After your artical I am interested to learn ASP .NET, could you tell me the best road map for it or good web-sites?

Thanks in advance

Satya

# re: Prevent Denial of Service (DOS) attacks in your web application

Sunday, March 25, 2007 5:19 AM by I Satya Sekhar

Hi

Ur artical is good. After your artical I am interested to learn ASP .NET, could you tell me the best road map for it or good web-sites?

Thanks in advance

Satya

(issekhar@gmail.com)

# re: Prevent Denial of Service (DOS) attacks in your web application

Monday, March 26, 2007 3:09 AM by omar

Hi Satya,

You will get many QuickStart tutorials that comes with Visual Studio. If you install MSDN Documentation, you will get many walkthroughs.

The internet is full of beginner articles. Check out www.codeproject.com

You can also try beginner books on ASP.NET.

# re: Prevent Denial of Service (DOS) attacks in your web application

Monday, March 26, 2007 9:35 PM by Dennis Gorelik

Omar,

Why wouldn't you call Response.End() in your validation method itself (if DOS attack is recognized)?

That trick would simplify the code on your pages.

# re: Prevent Denial of Service (DOS) attacks in your web application

Tuesday, March 27, 2007 1:05 AM by vikram

This was really very good stuff

# re: Prevent Denial of Service (DOS) attacks in your web application

Tuesday, April 03, 2007 2:30 PM by Shiva

Omar,

 Thanks for the info - it helps.

 I have concern about the scalability of the solution though.  Won't it be too much for the ASP.NET Cache to store one entry per user (who is online - which i assume in case of page flakes would be of the order of millions).  If I'm correct, your cache will start evicting the older HitInfo (even before the expiry time) as you add new HitInfo to it.  You can validate this by having a CacheItemRemovedCallback.

Shiva

# re: Prevent Denial of Service (DOS) attacks in your web application

Monday, April 30, 2007 7:16 PM by Nick

I have a question about the IsFirstVisit property. I don't see any documentation on it and I don't even see IsFirstVisit being a valid member of the DefaultProfile class.

Did I miss something?

Thanks,

 Nick

# re: Prevent Denial of Service (DOS) attacks in your web application

Monday, April 30, 2007 9:01 PM by omar

It's a custom boolean property that I added to Profile.

# re: Prevent Denial of Service (DOS) attacks in your web application

Monday, April 30, 2007 10:40 PM by Nick

So as long as my site does not allow cookieless visits (i.e. cookieless != true in sessionState)

need to worry at all about the piece of code in OnInit between the brackets:

if (!base.IsPostback){ if (Profile.IsFirstVisit)<--this code here> }

Thanks for you help & patience.

Nick

# re: Prevent Denial of Service (DOS) attacks in your web application

Monday, April 30, 2007 10:44 PM by Nick

Omar,

So if my site doesn't allow cookieless sessions,

can't I just omit the piece of code in OnInit where you check for FirstVisit and Revisit?

Thanks for your assistance & patience,

  Nick

# re: Prevent Denial of Service (DOS) attacks in your web application

Saturday, May 05, 2007 11:37 PM by omar

Someone can register and then use the logged in cookie to flood your system easily. So, you cannot trust registered users either.

# re: Prevent Denial of Service (DOS) attacks in your web application

Tuesday, May 22, 2007 9:15 PM by Paul

How do you maintain this in a web farm?  I am assuming tht Page Flakes runs on at least 10 servers.

# re: Prevent Denial of Service (DOS) attacks in your web application

Friday, May 25, 2007 4:23 AM by omar

Good question. Pageflakes runs only on 2 web servers and 1 DB server. So, we can get away with using standard ASP.NET cache. But for larger web farm, you will have to use distributed cache.

# re: Prevent Denial of Service (DOS) attacks in your web application

Monday, June 18, 2007 7:50 AM by reshma

i am new to this asp.net.

i need to develop a general component which can be included in any asp.net site,i need to reject a request from particular ip address ,if number of counts exceeds a particular number with in a particular time period say 1 min,which can be changed according to the administrators wish.

can i use this class for this requirement.or do i have to write httpmodule.if i use httpmodule is it possible to read xml file which contains max number of hits and time ?

plz help  itz urgent..

regards

reshma

# re: Prevent Denial of Service (DOS) attacks in your web application

Monday, June 18, 2007 9:51 PM by nile

i have gone through ur class.could u plz describe about HitInfo class and IsFirstVisit?

can u plz provide the full implementation of ActionValidator class .it will be a great help for a new develper like me..

plzz..

# re: Prevent Denial of Service (DOS) attacks in your web application

Tuesday, July 17, 2007 6:58 AM by Usman Masood

thanks omar, its good to see nice tricks and tips by you being shared.

Courageous effort. Keep it up.

# re: Prevent Denial of Service (DOS) attacks in your web application

Friday, July 27, 2007 9:54 AM by Juan

Many hardware devices can block DoS coming from a particular source to a particular destination when the traffic is exceeding a thresold in a defined period.

The hardware doesn't know which HTTP/HTTPS request is going to be processed, it simply will block it.

# re: Prevent Denial of Service (DOS) attacks in your web application

Monday, August 13, 2007 5:17 AM by Me

Hi,

the article was very informative.Could you please give us some more links on to Denial of service on web applications through acccount locking.

# re: Prevent Denial of Service (DOS) attacks in your web application

Thursday, August 16, 2007 4:45 PM by Pathik Thaker

let say if i have "Akamai Technologies" server and it is pinging to my application in this scenario what can be done ??? As I can not consider IP addesss in this scenario as DOS.

Can you guid me for this ???

Pathik

# re: Prevent Denial of Service (DOS) attacks in your web application

Tuesday, October 02, 2007 7:26 PM by Dmitriy Nagirnyak

You rely on context.Request.UserHostAddress which can be malformed by a good hacker. This is just basic protection. Anyway this is better than nothing :)

# re: Prevent Denial of Service (DOS) attacks in your web application

Thursday, October 04, 2007 7:59 PM by Abishek Bellamkonda

Mate, you write very interesting stuff. You do realise that if someone wants to do a DOS badly, you cannot stop it right?

Apart from shutting the machine.

# re: Prevent Denial of Service (DOS) attacks in your web application

Thursday, October 04, 2007 8:24 PM by Abishek Bellamkonda

IP addresses can be faked. As a matter of fact MAC addresses can b faked too. I don't know any solution that can really prevent DOS. Also organised DOS attack spread across a continent would be worst.

# 通过程序使你的网站预防DOS攻击的能力 --提高站点的安全性

Saturday, December 08, 2007 8:17 AM by jecray

如果不对客户端采取访问控制策略,一个网站很容易被DOS攻击。因此有必要采取措施。本文简单的介绍了如何通过程序预防dos攻击。

# re: Prevent Denial of Service (DOS) attacks in your web application

Friday, April 18, 2008 12:14 AM by Waleed Eissa

Hi Omar,

Thanks for your article, I wonder though whether there's any built-in features in IIS that could help stop DOS attacks. Your code is very good but the problem is that you have to make ASP.NET handle all files as the attack could be done by trying to download any type of files, images, js files .. etc

# re: Prevent Denial of Service (DOS) attacks in your web application

Monday, May 05, 2008 5:22 PM by Peter Tran

Great article.  However, I am trying to understand why your code does not allow search engines in?  Your code returns false for 'not valid' when checking for context.Request.Browser.Crawler.  Doesn't that prevent search engines from indexing your page?

# re: Prevent Denial of Service (DOS) attacks in your web application

Wednesday, June 25, 2008 2:48 PM by mlb

Hello Omar, question:

What about if it's a company using only one IP address(external) behind a router doing NAT? Employees try to access the webapp and will they be denied to access it?

# re: Prevent Denial of Service (DOS) attacks in your web application

Wednesday, June 25, 2008 4:02 PM by Google Me

This isn't DDOS prevention.

Your web server still has to accept the connection and work with it, thereby being busy.

So an attacker can still lock up your web server.

For a better DDOS prevention you have to work at the firewall level - but it's still not perfect.

# re: Prevent Denial of Service (DOS) attacks in your web application

Thursday, June 26, 2008 6:23 AM by omar

Waleed,

ASP.NET does not handle requests to static files like JS, CSS, html etc unless you have Wildcard mapping turned on. So, this code only protects calls going to ASP.NET

Peter Tran,

You can take out the Crawler check. My intention was to prevent crawler. But that prevents valid crawlers as well. You can also check if the Crawler name is "Unknown".

mlb,

Proxies that hide user's IP and uses the public IP of the proxy will be treated as one IP. So, you just adjust the threshold values in such a way that it allows such proxies, but also prevents request floods.

Google Me,

This prevents Application level DDOS to some extent. It saves your application from burning out CPU/DISK. As the check is minimal code, it takes much less CPU then actually executing a page or some functionality.

Network level DOS attacks are protected by Firewalls.

# re: Prevent Denial of Service (DOS) attacks in your web application

Monday, August 11, 2008 1:25 PM by Tarek

Can someone give me more info. on the following:

Profile.Isfirstvist??

Do we have to create this property.. It is not a profile property..

Where we getting the hitinfo() class from? I cant seem to find its source..

Any help is greatly appreciated..

# WHAT AM I MISSING?

Friday, August 29, 2008 4:52 PM by Joe

>>It's a custom boolean property that I added to Profile.

1. What is a "Profile?" What is a "HitInfo?" What is a "Profile.IsFirstVisit?" Are these things just pulled out of thin air? These things are unknown in MSDN.

2. Also, why is a "var" being used in C#?

>>var hit =(HitInfo)(context.Cache[key] ??

new HitInfo());

3. What class does OnInit derive from?

Am I the only one that cannot compile this example at all?

Do you have a downloadable file Omar? What references did you set up?

# re: Prevent Denial of Service (DOS) attacks in your web application

Wednesday, September 03, 2008 3:33 AM by J

Denial of Service Attack Prevention should be done at Hardware/Firewall leve, NOT in your web-application.

It is too expensive and error-prone to do it in your application. FireWalls/Hardware/Routers are adept at doing such a thing.

# re: Prevent Denial of Service (DOS) attacks in your web application

Wednesday, September 03, 2008 3:43 AM by omar

Please read this para:

"Of course you can put in some Cisco firewall and prevent DOS attack. You will get guaranty from your hosting provider that their entire network is immune to DOS and DDOS (Distributed DOS) attacks. What they guaranty is network level attack like TCP SYN attacks or malformed packet floods etc. There is no way they can analyze the packet and find out a particular IP is trying to load the site too many times without supporting cookie or trying to add too many widgets. These are called application level DOS attack which hardware cannot prevent. It must be implemented in your own code."

You cannot add logics like someone is trying to add too many widgets on your Firewall/Hardware/Routers.

# re: Prevent Denial of Service (DOS) attacks in your web application

Tuesday, September 16, 2008 1:14 PM by Andrew

Hi Omar,

Thanks for the info, I was wondering why you dont replace the cached item after updating the HitInfo.Hit? Is the object in cache a different copy of the object that is incremented?

"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);"

Why not

"

if (hit.Hits > 1) {

  Cache.Remove(key);

}

Cache.Add(<all those params>);

"

# re: Prevent Denial of Service (DOS) attacks in your web application

Tuesday, September 16, 2008 1:31 PM by omar

As the cache is in-memory cache, the Hit object is referenced as By Ref. So, making any modification to the object updates the actual object inside the cache.

# re: Prevent Denial of Service (DOS) attacks in your web application

Monday, October 13, 2008 2:05 AM by Psul

Why you didn't write this ddos-protection code in HttpModule. It will be faster to process request and denie them (if ddos detected) on HttpModule level, isn't it?

# re: Prevent Denial of Service (DOS) attacks in your web application

Monday, October 13, 2008 2:57 AM by omar

Don't want to do the calculation on each and every call. Only where expensive operations are performed.

# re: Prevent Denial of Service (DOS) attacks in your web application

Monday, October 13, 2008 5:29 AM by Aristos

This is a joke or a bug ?

 if( context.Request.Browser.Crawler )

return false; <----

you do not won crawlers on your site ?

# re: Prevent Denial of Service (DOS) attacks in your web application

Monday, November 03, 2008 12:42 PM by James

I need help! Someone threatened to ddos my site! What should i do?!

# re: Prevent Denial of Service (DOS) attacks in your web application

Wednesday, July 08, 2009 9:55 PM by KiwiCoder

I created the following to replace the Profile.IsFirstVisit

public bool IsFirstVisit()

{

if (Session["IsFirstVisit"] == null)

{

Session["IsFirstVisit"] = "false";

return true;

}

else

{

return false;

}

}

# clean credit

Monday, October 05, 2009 10:59 AM by clean credit

I only wish I had found it sooner.

Leave a Comment

(required) 
(required) 
(optional)
(required)