همانطور که میدانید وب سایتهای اینترنتی در معرض انواع و اقسام حملات قرار دارند و یکی از این حملات Dos است. در این نوشتار میخواهیم تکه کدی را ارائه دهیم، تا این نوع حملات را دفع نماید. همانطور که میدانید یک درخواست Http باید از ماژولهای مختلفی عبور نماید تا به یک Http Handler برسد.
ابتدا باید یک Enum تعریف کنیم تا نوع درخواست کاربر را مشخص کند. مثلا 100 درخواست ابتدایی را به عنوان FirstVisite در نظر گرفته و اگر تعداد درخواستها از 100 گذشت، در دسته Revisit قرار میگیرند و ... . البته این بستگی به شما دارد که مقادیر را چقدر در نظر بگیرید؛ اما دقت کنید.
private enum VisiteType { FirstVisite = 2, Reviste = 4, }
در مرحله بعدی باید آدرس Ip بیننده سایت را بدست آورده وچک کنیم که این آدرس Ip در کش موجود هست یا خیر. اگر موجود بود مقدار متغیر hits را افزایش میدهیم و چک میکنیم که متغیر با کدام یک از مقادیر Enum برابری میکند و آن را در کش سیستم ذخیره میکنیم.
if (httpContext.Cache[ipAddress] != null) { hits++; if (hits == (int)VisiteType.FirstVisite) { httpContext.Cache.Insert(key: ipAddress, value: hits, dependencies: null, absoluteExpiration: DateTime.UtcNow.AddSeconds(1), slidingExpiration: Cache.NoSlidingExpiration); return; }
در تکه کد بالا چون درخواست به حد معین و معقولی رسیده است، آدرس بعد از یک ثانیه از کش حذف میشود. اما اگر درخواستهای غیرمعقولی به سرور ارسال شود، باید پاسخ را قطع و آدرس Ip را در کش ذخیره و این آدرس Ip باید به مدت معینی در کش مانده و بلاک شود.
using System; using System.Net; using System.Web; using System.Web.Caching; namespace IpBlocker { public class IpBlocker : IHttpModule { private int hits = 0; /// <summary> /// Define enum to specify visite type /// </summary> private enum VisiteType { FirstVisite = 2, Reviste = 4, } public void Init(HttpApplication context) { context.BeginRequest += OnBeginRequest; } public void Dispose() { } public void OnBeginRequest(object sender, EventArgs e) { var httpApplication = sender as HttpApplication; var httpContext = httpApplication?.Context; ProcessRequest(httpApplication, httpContext); } private void ProcessRequest(HttpApplication application, HttpContext httpContext) { //Checke if browser is a search engine web crawler if (httpContext.Request.Browser.Crawler) return; var ipAddress = application.Context.Request.UserHostAddress; if (httpContext.Cache[ipAddress] == null) { // Reset hits for new request after blocking ip if (hits > 0) hits = 0; hits++; httpContext.Cache.Insert(key: ipAddress, value: hits, dependencies: null, absoluteExpiration: DateTime.UtcNow.AddSeconds(1), slidingExpiration: Cache.NoSlidingExpiration); return; } else { if (httpContext.Cache[ipAddress] != null) { hits++; if (hits == (int)VisiteType.FirstVisite) { httpContext.Cache.Insert(key: ipAddress, value: hits, dependencies: null, absoluteExpiration: DateTime.UtcNow.AddSeconds(1), slidingExpiration: Cache.NoSlidingExpiration); return; } if (hits == (int)VisiteType.Reviste) { httpContext.Cache.Insert(key: ipAddress, value: hits, dependencies: null, absoluteExpiration: DateTime.UtcNow.AddSeconds(1), slidingExpiration: Cache.NoSlidingExpiration); return; } if (hits > (int)VisiteType.Reviste) { httpContext.Cache.Insert(key: ipAddress, value: hits, dependencies: null, absoluteExpiration: DateTime.UtcNow.AddMinutes(1), slidingExpiration: Cache.NoSlidingExpiration); httpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden; httpContext.Response.SuppressContent = true; httpContext.Response.End(); } } } } } }
در کد بالا محدودیت زمانی یک دقیقه در نظر گرفته شده است.