جلوگیری از حملات sql injection در asp.net – قسمت دوم

تاریخ انتشار : دی ۳, ۱۳۹۷
1 ستاره2 ستاره3 ستاره4 ستاره5 ستاره

در این بخش با مقاله ای با موضوع جلوگیری از حملات sql injection در asp.net در خدمت شما عزیزان خواهیم بود.

این مقاله ترجمه یکی از مقالات سایت Mikesdotnetting می باشد. در این مقاله سعی شده حملات sql injection بررسی شود و راه های مقابله با آن نیز آموزش داده شوند.

قسمت دوم :

در این حالت متغیر ID می تواند از فرم دیگر یا از طریق مقداردهی QueryString شاید از یک Hyperlink در صفحه قبلی بیاید. این برای کاربران بدخواه بسیار راحت است که مقدار یک QueryString را تغییر دهند. در تصویری زیر که توسط Debugger ویژوال استودیو گرفته شده من فقط متن Drop Table Admin; را در انتهای QueryString اضافه کردم :

حملات sql injection

دوباره یک کد sql در دیتابیس اجرا می شود و نتیجه آن این است که Table Admin در دیتابیس پاک می شود. باید متعجب باشید که هکر چطور نام جدول شما را می داند. آیا بصورت شانسی وارد کرده یا خیر؟ اما چگونه این نام را بدست آورده؟؟ آنھا از نام ھایی استفاده میکنند که ھدف آنھا را میسر میسازد. این زیاد وقت گیرنیست که بشود آنھا را حدس زد و البته اگر از ASP.NET Membership خارج از سیستم استفاده کرده باشید aspneddb.mdf schema برای همه قابل دسترسی خواهد بود اما قبل از آن که شروع کنید نام جدول ھای خود را به اسامی غیر معمول تغییر دھید بدانید که این کار جواب این مشکل نیست.

این مثال نشان میدھد کھ حملھ ھا میتوانند بسیار غم انگیز و پردردسر باشند یک نفر میتواند CMS شما را تجزیه کند و محتوبات سایت شما را تغییر دهد و یا اینکه قسمتی از دیتا بیس شما را نابود کنند آیا این درست است که Backup می توانند همه چیز را به حالت اول بازگرداند؟ یا شاید آنها بتوانند یک عضو از سایت شما شوند و به قسمت های محافظت شده شما دسترسی پیدا کنند که کاربران شما مایل نیستند دیگران آنھا را ببینند یا شاید بتوانند ضرر ھای بدتری وارد کنند.

Penetration Tests تست هایی هستند برای شناخت حفره های امنیتی در نرم افزار سیستم یا شبکه. این تست ها از Store Preceedure سیستمی SQL Server XP cmdshell استفاده می کنند. بصورت فوق العاده ای قوی هست و به کاربران دسترسی کلی کنترل سیستم را می دهند.

جلوگیری

مطمئن ھستم که اکنون مشاھده میکنید که فقط چیزھای قابل درک توست سیستم باعث میشوند که نرم افزار شما مورد حمله موفق قرار گیرد حال ما از آنھا جلوگیری میکنیم من تعدادی توصیه شبیه به این (http://forums.asp.net/t/1254125.aspx ) دیده ام که یک لیست سیاه از تمامی دستوراتی که میتوانند مورد استفاده قرار گیرند درست کنید اگر در ورودی کاربر وجود داشت اجازه
اجرا ندھید اما این از نظر من روش مناسبی نیست دو مشکل اساسی در این رابطه میتوان دید اول اینکه چرا کاربران نباید حتما مقادیری وارد کنندکه در لیست سیاه وجود دارد؟؟ چند درصد کاربران جلوگیری میکنند از اینک متن ورودی آنھا شبیه به At the end of the day نباشد؟؟ اکثر دستوران sql شبیه مکالمه روزانه ما هستند یا اینکه چرا انها نباید از علامت @ استفاده کنند؟

مشکل دوم اینکه چه اتفاقی میافتد اگر مایکروسافت تغییری در دستورات Sql دھد؟ آیا شما به تمام نرم افزارھایی که در طول سال نوشته اید برمیگردید و آنھارا دوباره اصلاح میکنید؟ راه منطقی برای جلوگیری از sql injection استفاده از Parameter Query هست.

Parameter Queries

پارامتر ھا در کوئری محلی ھستند برای نگھداری مقادیر ورودی که در زمان اجرا به متن کوئری اضافه میشوند پارامتر ھای sql رفتاری مانند پارامترها در #C از خود بروز می دهند و میتوان مقدار و نوع متغیر را در آنھا مشخص کرد و درصورتی که مثلا بخواھید متنی را به Int تبدیل کنید در صورت عدم امکان Exception مربوطه فعال میشود در مثال قبل زمانی که مقدار Productld مقدار دهی شد با دستوری که باعث از بین رفتن جدول شود ھیچ خطایی گرفته نشد در حالی که سمیکالن و متن قابل تبدیل بھ عدد نبودند!!

کلاس sqlcommand یک کوئری یا Procedure رو آماده میکنه برای اینکه به اجرا در بیاد برای ھر پارامتری که در دستور کوئری وجود داره شما نیاز دارید که یک پارامتر ب این مجموعه اضافه کنید میتوان با مثالی آنرا توضیح داد پس ھمان مثال بالا را با این متد بازنویسی میکنیم.

protected void Page_Load(object sender, EventArgs e)
{
var connect = ConfigurationManager.ConnectionStrings[“NorthWind”].ToString();
var query = “Select * From Products Where ProductID = @ProductID”;
using (var conn = new SqlConnection(connect))
{
using (var cmd = new SqlCommand(query, conn))
{
cmd.Parameters.Add(“@ProductID”, SqlDbType.Int);
cmd.Parameters[“@ProductID”].Value = Convert.ToInt32(Request[“ProductID”]);
conn.Open();
//Process results
}
}
}

کانکشن استرینگ میتواند توسط کلاس arkred”>System.Configuration.ConfigurationManager” که اجازه میدھد به فایل web.config دسترسی داشته باشید مقداردھی شود در این مثال کوئری با پارامتر @ProductID کامل میش ھمه پارامتر ھا با @ شروع میشوند به این دلیل تعریف کانکشن در بلوک using قرار داده شده که نیازی نباشد بعدا آنرا با کد Dispose کنیم.

دو متد برای اضافه کردن پارامتر ھا به کالکشن موجود است یکی متد “Add()” و دیگری “AddWithValue()” . متد اول برای overload دارد من از Add(String, SqlDbType) استفاده کردم و اون رو جداگانه بصورت زیر مقداردهی کردم :

cmd.Parameters.Add(“@ProductID”, SqlDbType.Int).Value =
Convert.ToInt32(Request[“ProductID”]);

 

در ادامه از متد AddWithValue(string, object) بصورت زیر استفاده میشود :

protected void Page_Load(object sender, EventArgs e)
{
var connect = ConfigurationManager.ConnectionStrings[“NorthWind”].ToString();
var query = “Select * From Products Where ProductID = @ProductID”;
using (var conn = new SqlConnection(connect))
{
using (var cmd = new SqlCommand(query, conn))
{
cmd.Parameters.AddWithValue(“@ProductID”, Convert.ToInt32(Request[“ProductID”]);
conn.Open();
//Process results
}
}
}

 

انتخاب با شماست اما معمولا بصورت حرفه ای از متد Add() برای مشخص کردن نوع داده و طول اون استفاده میکنند . اون باعث جلوگیری از تبدیلات غیر ضروری و بار اضافی روی سرور می شود و ھمچنین باعث اطمینان از نوع متغیر و جلوگیری از خطا میشود. زمانی که ADO.NET دستور را به سرور ارسال میکند سرور Store Procedure زیر را اجرا میکند :

exec sp_executesql N’Select * From Products Where ProductID = @ProductID’,N’@ProductID
int’,@ProductID=13

 

در این دستود ابتدا متن دستور سپس پارامترھای مربوطه به ھمراه نوع آنھا و در آخر مقدار پارامتر میاید مقدار داده شده بصورت string می باشد و در دستورات sql مقدار ها باید بصورت متغیرهای string باشند و نه بخشی از دستور و به این صورت است که از sql injection جبوگیری می شود.

استفاده از این روش سود دیگری ھم دارد و آن ھم در افزایش بازدھی سیستم میباشد زمانی که sql server می خواهد دستوری را اجرا کند ابتدا بدنبال دستور بارگذاری شده ای شبیه آن میگردد اگر آنرا پیدا کند از روشی که قبلا برای آن درست کرده که بصورت موثری در بھبود بازدھی موثر است استفاده میکند و اگر دقیقا این دستور بارگذاری شده را پیدا نکند ابتدا سعی میکند یک روش برای بالابردن کارایی این دستور بسازد و سپس به اجرای این دستور میپردازد و اگر دستور بصورت دینامیک ایجاد شود و ھر بار متغیر ھا در متن دستور بیایند سیستم ھربار باید دوباره این روش را بسازد و این باعث پایین آمدن قدرت سیستم میشود.

Stored Procedures

این برای من جالب ھست که ھربار در فروم asp.net به بحث در رابطه با injection پرداخته می شود روی این موضوع تاکید می شود که حتما باید از Stored Procedures استفاده شود تا بتوان از پارارمتر ھا استفاده کرد ھمانطور که قبل از این اثبات شده این موضوع درست نمی باشد.

به ھرحال زمانیکه از Stored Procedures برای کد نویسی استفاده میکنید باید به دو نکته توجه کنید: اول اینکه باید از نام Stored Procedures بجای متن دستور استفاده کنید و دوم اینکه شما باید “CommandType” را به “CommandType.StoredProcedure” تغییر دھید زیرا سیستم بصورت پیشفرض آن را بصورت دستور sql می شناسد. کد زیر تصحیح شده با Stored Procedures است :

var connect = ConfigurationManager.ConnectionStrings[“NorthWind”].ToString();
var query = “GetProductByID”;
using (var conn = new SqlConnection(connect))
{
using (var cmd = new SqlCommand(query, conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(“@ProductID”, SqlDbType.Int).Value =
Convert.ToInt32(Request[“ProductID”]);
conn.Open();
//Process results
}
}

 

LINQ to SQL, Entity Framework, OleDb and ODBC

هم LinQ to sql و هم Entity Framework دستورات sql را بصورت پارامتری درست می کنند و بصورت ایمن در برایر حملات sql injection می باشند اگر شما از Ms Acces استفاده می کنید نیازی نیست که نگران این حملات باشید زیر access محدودتر از آن است که بتوان این عملیات را روی آن انجام داد و بعنوان مثال همان دستور Drop Table در Access کار نخواهد کرد با این حال مثال هک در لاگین در access هم کار می کند پس باید همچنان از پارامترها استفاده کنید.

در سیستم ھای دیتابیس ھای دیگر ھم این روش ھا وجود دارد و شما باید در ھر سیستم از پارامتر ھای منطبق بر ھمان سیستم استفاده کنید تا به دیگران اجازه اجرای حملات ندھید.

پایان

 

 

 


نظرات

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *