The Article is an understanding from Omar Al Zabir (C# MVP) book’s on ASP.NET.
Web services are the most attractive target for cyber-terrorists as a naughty Coder can easily bring down a server by repeatedly calling a web service which does expensive work.
Consider the following masterpiece, which is enough to jeopardize your site.
for( int i = 0; i < 100000; i ++ )
{
WebClient client = new WebClient();
client.DownloadString("Your Service URL");
}
So what would be the salvation process.The trick that has been used here is an inexpensive way to remember how many requests are coming from a particular IP. When the number of request exceeds the melting point, 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 15 mins. After 15 mins, again allow requests from that IP.
Here is a class named ActionValidator which maintains a count of specific actions like First Visit, Revisit, Asynchrnous postbacks etc. It checks whether the count for such specific action for a specific IP exceeds the melting point or not.
public static class ActionValidator {
private const int DURATION = 15; // 15 min period
public enum ActionTypeEnum
{ FirstVisit = 100, // The most expensive one, choose the valu wisely.
ReVisit = 1000, // Welcome to revisit as many times as user likes
Postback = 5000, // post bact count
}
}
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.
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;
}
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.
private class HitInfo
{
public int Hits;
private DateTime _ExpiresAt = DateTime.Now.AddMinutes(DURATION);
public DateTime ExpiresAt { get { return _ExpiresAt; } set { _ExpiresAt = value; } }
}
The usage is very simple:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
// Check if revisit is valid or not
if( !base.IsPostBack )
{
// Block cookie less visit attempts
if( Profile.IsFirstVisit )
{
if( !ActionValidator.IsValid(ActionValidator.ActionTypeEnum.FirstVisit) Response.End();
}
else
{
if( !ActionValidator.IsValid(ActionValidator.ActionTypeEnum.ReVisit) ) Response.End();
}
}
else
{
// Limit number of postbacks
if( !ActionValidator.IsValid(ActionValidator.ActionTypeEnum.Postback) Response.End();
}
}
Thanks Omar Al Zabir for making us aware about such threat.
No comments:
Post a Comment