مقدمه :
وب سرويس ها مي توانند هدف جذابي براي هکرها باشند ، زيرا هر هکر آماتوري مي تواند با فراخواني متناوب و مکرر يک وب سرويس توسط يک حلقه تکرار ، باعث اختلال در کار سرور و حتي از کار افتادن آن شوند.(Denial of Service)
در اين ميان سايتهايي که به منظور web 2 طراحي شده اند و داراي صفحه شروع با تکنولوژي آژاکس (Ajax) هستند ، در معرض خطر بيشتري مي باشند.
به طور مثال سايت PageFlakes را در نظر بگيريد. اين سايت مي تواند بهترين هدف براي هکرها باشد. وقتي شما براي اولين بار از اين سايت ديدن مي کنيد ، از شما خواسته مي شود که صفحه اول را براي خود سفارشي سازي کنيد. که اين کار با فراخواني يک وب سرويس با استفاده از تکنولوژي آژاکس انجام مي شود و پس از سفارشي سازي صفحه ، تغييرات شما در کوکي مرورگرتان ذخيره مي شوند.
اگر شما اجازه ذخيره تغييرات را در کوکي ها ندهيد (ويژگي کوکي ها را در مرورگر خود غير فعال کرده باشيد) ، شما با بازديد مکرر و پشت سر هم از صفحه اول سايت باعث فراخواني مکرر وب سرويس مربوطه شده و باعث آسيب رساندن به سايت مربوطه و سرور آن خواهيد شد.
اي عمل توسط چند خط کد مي تواند انجام شود که در زير آن را مشاهده مي کنيد.
for (int i = 0; i < 100000; i++)
{
WebClient client = new WebClient();
client.DownloadString("http://www.pageflakes.com/default.aspx");
}
|
با اين که روش ياد شده جهت حمله به يک وب سرويس ، بسيار ساده مي باشد ولي جالب است بدانيد که بسياري از سايتها نسبت به اين آسيب پذيري ايمن نمي باشند. در اين مقاله روش جلوگيري از اين نوع حملات را مورد بحث قرار خواهيم داد.
شروع از ابتدا:
در ابتدا فرض مي کنيم که کاربر مي تواند سه حالت داشته باشد :
- براي اولين بار از صفحه ديدن مي کند (هنوز سفارشي سازي نکرده و تغييرات در کوکي ها ذخيره نشده اند)
- براي چندمين بار از صفحه ديدن مي کند ( تغييرات ذخيره شده اند)
- کاربر در صفحه در حال Post Back کردن باشد.
براي هر حالت ما حداکثر تعداد دفعاتي که کاربر مجاز است اين عمل را انجام دهد را تعيين مي کنيم. ما در اينجا فرض را بر آن مي گيرم که کاربر در يک بازه زماني دلخواه ( در اينجا ما 10 دقيقه در نظر مي گيريم) ، حق دارد 100 مرتبه براي اولين بازديد ، 100 مرتبه براي بازديد مجدد و 1000 بار براي Post Back کردن درخواست دهد و اگر بيشتر از اين دفعات در ظرف 10 دقيقه انجام شود ، ما آن درخواست را طبق روشي که در ادامه شرح داده خواهد شد ، حذف مي کنيم.
لازم به ذکر است که کاربر پس از 10 دقيقه مجددا مي تواند درخواست هاي خود را جهت بازديد از صفحه يا فراخواني وب سرويس انجام دهد.
براي شمارش تعداد درخواست هاي کاربر ، نياز داريم که مشخصه IP کاربر را همراه با تعداد درخواست او ، ذخيره کنيم.
در قطعه کد زير کلاسي به نام ActionValidator نوشته ايم که داراي يک ساختار شمارشي (enum) به نام ActionTypeEnum مي باشد. اين ساختار نوع درخواست کاربر و حداکثر تعداد مجاز درخواست کاربر را نگهداري مي کند.
private const int DURATION = 10; // 10 min period
public enum ActionTypeEnum
{
FirstVisit = 100, // The most expensive one, choose the value wisely.
ReVisit = 100, // Welcome to revisit as many times as user likes
Postback = 1000, // Not must of a problem for us
}
|
در اين قسمت متد استاتيکي نوشته ايم به نام IsValid ، که در صورتي که درخواست کاربر مجاز باشد ، مقدار true و در صورتي که تعداد درخواست هاي کاربر بيشتر از حد مجاز باشد ، مقدار false را برمي گرداند. تعداد درخواست هاي کاربر و IP مربوط به آن در حافظه پنهان (Cache) نگهداري مي شوند.
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;
}
|
کلاس HitInfo صفتي به نام Hits دارد که تعداد دفعات درخواست کاربر را نگهداري مي کند.
خوب اکنون زمان استفاده از کلاسي که نوشته ايم رسيده است. بدين منظور رويداد OnInit مربوط به صفحه را override مي کنيم.
کنترل مي کنيم که اگر درخواست کاربر غير مجاز بود ، آن را با دستور Response.End حذف مي کنيم و در غير اين صورت اجازه ادامه کار را به آن خواهيم داد.
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 (Convert.ToBoolean(Profile.IsFirstVisit))
{
if (!ActionValidator.IsValid(ActionValidator.ActionTypeEnum.FirstVisit)) Response.End();
Profile.IsFirstVisit = "false";
}
else
{
if (!ActionValidator.IsValid(ActionValidator.ActionTypeEnum.ReVisit)) Response.End();
}
}
else
{
// Limit number of postbacks
if (!ActionValidator.IsValid(ActionValidator.ActionTypeEnum.Postback)) Response.End();
}
}
|
همانطور که مشادهده کرديد راه حل جلوگيري از اين نوع حملات بسيار ساده و در عين حال بسيار مؤثر مي باشد.
برنامه نوشته شده از طريق لينک بالاي صفحه قابل دانلود مي باشد.