I've written this module (using a tutorial on the web I can't find now to stop unusual requests from clients. It's working as I've tested it on a local system.
Is the logic fine enough?
Another problem is that it counts requests for non-aspx resources (images, css, ...), but it shouldn't. How can I filter request for aspx pages ?
This is the module code:
public class AntiDosModule : IHttpModule
{
const string blockKey = "IsBlocked";
const string reqsKey = "Requests";
public void Dispose()
{ }
public void Init(HttpApplication context)
{
context.BeginRequest += ValidateRequest;
}
private static void ValidateRequest(object sender, EventArgs e)
{
// get configs from web.config
AntiDosModuleSettings setting = AntiDosModuleSettings.GetConfig();
int blockDuration = setting.IPBlockDuration;
// time window in which request are counted e.g 1000 request in 1 minute
int validationTimeWindow = setting.ValidationTimeWindow;
// max requests count in specified time window e.g 1000 request in 1 minute
int maxValidRequests = setting.MaxValidRequests;
string masterKey = setting.MasterKey;
HttpContextBase context = new HttpContextWrapper(HttpContext.Current);
CacheManager cacheMgr = new CacheManager(context, masterKey);
// is client IP blocked
bool IsBlocked = (bool)cacheMgr.GetItem<Boolean>(blockKey);
if (IsBlocked)
{
context.Response.End();
}
// number of requests sent by client till now
IPReqsHint hint = cacheMgr.GetItem<IPReqsHint>(reqsKey) ?? new IPReqsHint();
if (hint.HintCount > maxValidRequests)
{
// block client IP
cacheMgr.AddItem(blockKey, true, blockDuration);
context.Response.End();
}
hint.HintCount++;
if (hint.HintCount == 1)
{
cacheMgr.AddItem(reqsKey, hint, validationTimeWindow);
}
}
}
internal class IPReqsHint
{
public int HintCount { get; set; }
public IPReqsHint()
{
HintCount = 0;
}
}
and this is the CacheManager class:
public class CacheManager
{
HttpContextBase context;
string masterKey;
public CacheManager(HttpContextBase context, string masterKey)
{
this.context = context;
this.masterKey = masterKey;
}
public void AddItem(string key, object value, int duration)
{
string finalKey = GenerateFinalKey(key);
context.Cache.Add(
finalKey,
value,
null,
DateTime.Now.AddSeconds(duration),
System.Web.Caching.Cache.NoSlidingExpiration,
System.Web.Caching.CacheItemPriority.Normal,
null);
}
public T GetItem<T>(string key)
{
string finalKey = GenerateFinalKey(key);
var obj = context.Cache[finalKey] ?? default(T);
return (T)obj;
}
string GenerateFinalKey(string key)
{
return masterKey + "-" + context.Request.UserHostAddress + "-" + key;
}
}