TAHA
09-30-2009, 06:01 AM
در این بخش به بررسی برخی نکات خاص در خصوص ایمن سازی برنامه های وب با تمرکز بر روی کنترل های Validation خواهیم پرداخت .
تهدیدات امنیتی در صورت عدم ارزیابی داده ورودی
برنامه های وب ، داده مورد نیاز خود را از طریق درخواست های مبتنی بر پروتکل HTTP دریافت می نمایند ( در برخی موارد ممکن است داده مورد نیاز یک برنامه وب از طریق یک فایل تامین گردد). با توجه به ماهیت پروتکل فوق ، مهاجمان می توانند هر بخشی از یک درخواست HTTP نظیر url ، querystring ، هدر ، کوکی ها ، فیلدهای موجود بر روی فرم و فیلدهای مخفی را تحریف تا ضمن نادیده گرفتن مکانیزم های امنیتی بکارگرفته شده در یک سایت ، آن را با مشکلات امنتیی متعددی مواجه نمایند. حملات forced browsing, command insertion, cross site scripting, buffer overflows, format string attacks و SQL injection نمونه هائی در این زمینه می باشند .
تعداد زیادی از برنامه های وب صرفا" از مکانیزم های سمت سرویس گیرنده به منظور بررسی و ارزیابی داده ورودی استفاده می نمایند . مهاجمان با استفاده از روش های متفاوتی می توانند مکانیزم های استفاده شده به منظور ارزیابی داده ورودی را نادیده گرفته و برنامه های وب را در مقابل داده ورودی مخرب خلع سلاح نمایند . مهاجمان ، بدین منظور می توانند با استفاده از ابزارهائی نظیر telnet درخواست های HTTP را تولید نمایند . بدیهی است در چنین مواردی نباید انتظار داشت آنان واکنش هائی را که مد نظر پیاده کنندگان برنامه های وب در سمت سرویس گیرنده است ، انجام دهند . با این که بررسی و ارزیابی داده ورودی در سمت سرویس گیرنده یک ایده عالی است و می تواند به عنوان یک اقدام مناسب در جهت افزایش کارآئی برنامه های وب تلقی گردد ولی قطعا" رویکرد فوق دارای مزیت امنیتی خاصی نخواهد بود .
به منظور ارزیابی داده ورودی می بایست از روش های سمت سرویس دهنده استفاده گردد تا یک لایه دفاعی مناسب به منظور پیشگیری از درج داده مخرب توسط مهاجمان ایجاد گردد . پس از تحقق خواسته فوق ، می توان با دقت اقدام به بهینه سازی روش های استفاده شده به منظور بررسی و ارزیابی داده ورودی در سمت سرویس گیرنده نیز نمود تا ترافیک غیرضروری بر روی سرویس دهنده به حداقل مقدار ممکن برسد .
بررسی یک نمونه
در برخی موارد از داده ورودی در یک TextBox به منظور ایجاد یک query در ارتباط با یک بانک اطلاعاتی استفاده می گردد . روش فوق ، ممکن است مسائل و مشکلات امنیتی متعددی را به دنبال داشته باشد ( از عدم اجرای اسکریپت ها گرفته تا بروز اشکال در بانک اطلاعاتی ) . مجددا" لازم است به این نکته مهم اشاره گردد که کنترل های validation ، به منزله اولین لایه دفاعی در مقابل درج داده مخرب محسوب می گردند و این اطمینان را ایجاد می نمایند که صرفا" داده معتبر در اختیار سایر لایه های یک برنامه خصوصا" لایه داده آن قرار داده خواهد شد .
مهاجمان می توانند از طریق TextBox استفاده شده بر روی یک فرم ، کدهای مخربی را به سیستم وارد نمایند که حذف تمامی بانک اطلاعاتی را به دنبال داشته باشد . با این که همواره فرض پیاده کنندگان برنامه های وب بر این است که از TextBox برای درج داده در سیستم استفاده خواهد شد ، ولی واقعیت این است که ممکن است از آنها برای درج کد نیز استفاده گردد . SQL injection یک نمونه از تهدیدات موجود در این زمینه است .
SQL Injection
فرض کنید از یک TextBox برای درج داده بر روی یک فرم استفاده شده باشد و پس از درج داده توسط کاربر ، از آن به منظور بازیابی رکوردهائی خاص از یک بانک اطلاعاتی استفاده می گردد . بدین منظور ، از دستور SELECT به صورت زیر استفاده شده است :
SQLString = "SELECT * FROM MyTable WHERE MyKey = '" & MyTextBox.Text & "'"
دستور SELECT ، به صورت پویا از مقدار درج شده در TextBox استفاده می نماید . ظاهرا" همه چیز درست است و مشکل خاصی وجود نخواهد داشت ولی فرض کنید کاربری کد SQL زیر را در TextBox وارد نماید :
Search :
پس از درج داده فوق در TextBox ، وضعیت query نوشته شده در برنامه به صورت زیر خواهد بود :
SELECT * FROM MyTable WHERE MyKey = ' ' ; DROP DATABASE MyDatabase
در چنین مواردی ، عبارت SQL شامل دو دستور مجزاء می گردد که اولین دستور آن با توجه به ماهیت داده ورودی مقدار null خواهد بود و عملا" رکوردی را برنمی گرداند و دومین عبارت SQL ، باعث حذف یک بانک اطلاعاتی خواهد شد . بدین ترتیب یک SQL injection محقق می گردد و کد مخرب با داده مورد انتظار در عبارت SQL جایگزین می شود. با این که در یک بانک اطلاعاتی اکسس ، نمی توان چندین عبارت SQL را در یک خط استفاده نمود ولی برخی از سیستم های مدیریت بانک های اطلاعاتی قادر به اجراء کد فوق خواهند بود .
پیاده کنندگان برنامه های وب می توانند از کنترل های validation به منظور بلاک نمودن اینچنین کدهائی استفاده نمایند . بدین منظور می توان طول رشته ورودی ، نوع داده ورودی و یا وجود داده ورودی در یک محدوده خاص را بررسی نمود . تست های فوق در مواردی که داده ورودی از نوع string و با طول نامشخص باشند ، کارساز نبوده و نمی توان از کنترل های اشاره شده در جهت ایجاد یک سطح حفاظتی مناسب استفاده نمود .
راه حل چیست ؟
بهترین روش برای حفاظت در مقابل ورود کدهای مخرب به سیستم ، استفاده از عبارات SQL به صورت پارامتریک در مقابل بکارگیری مستقیم داده ورودی است . پارامترها ، مکان لازم برای نگهداری مقادیر داده را فراهم نموده و این اطمینان را ایجاد می نمایند که از مقادیر ورودی مستقیما" در کد استفاده نخواهد شد .
در کد زیر از یک عبارت SELECT به منظور بازیابی رکوردهائی خاص از جدول Books در بانک اطلاعاتی BooksDB استفاده شده است . عبارت SQL به عنوان خصلت SelectCommand کنترل منبع داده AccessDataSource ( با " id="BookSource ) در نظر گرفته شده است .
Sub Get_Record (Src As Object, Args As EventArgs)
Dim SQLString As String
SQLString = "SELECT BookID, BookTitle, BookPrice FROM Books" & _
"WHERE BookID = @BookID"
BookSource.SelectCommand = SQLString
End Sub
یک پارامتر با استفاده از نام خود که به دنبال یک کاراکتر "@" می آید ( در این مثال BookID @ ) ، مشخص می گردد و یک مرجع به داده ورودی است که در عبارت SELECT و به منظور بازیابی رکوردهای مورد نظر استفاده می گردد . فرض کنید ، کاربر داده زیر را در TextBox وارد نماید :
Book ID :
مقدار ورودی در TextBox ، به عنوان مقدار پارامتر BookID @ در عبارت SELECT در نظر گرفته می شود . در چنین مواردی ، می بایست با صراحت مقدار درج شده در TextBox را با پارامتر فوق مرتبط نمود . زمانی که از کنترل AccessDataSource به منظور بازیابی داده از یک بانک اطلاعاتی استفاده می گردد ، برای مشخص کردن پارامترهای مورد نیاز در یک عبارت SELECT ، می بایست از بخش <SelectParameters> در کنترل استفاده گردد . در این بخش می توان از یک و یا چندین کنترل <asp:ControlParameter> استفاده نمود . با استفاده از کنترل <asp:ControlParameter> ، می بایست یک نام را برای پارامتر در نظر گرفت .همچنین ، لازم است کنترلی که قرار است مقدار آن به عنوان پارامتر در نظر گرفته شود نیز مشخص گردد.
کد زیر نحوه استفاده از پارامتر BookID @ در کنترل AccessDataSource را نشان می دهد .
Book ID:
<asp:TextBox id="BookIDInput" Runat="Server"/>
<asp:Button Text="Find" OnClick="Get_Record" Runat="Server"/>
<asp:AccessDataSource id="MySource" Runat="Server" DataFile="../DB/BooksDB.mdb">
<SelectParameters>
<asp:ControlParameter Name="BookID" ControlID="BookIDInput" PropertyName="Text"/>
</SelectParameters>
</asp:AccessDataSource>
توضیحات :
کنترل <asp:ControlParameter> از سه خصلت به منظور ایجاد ارتباط با کنترلی که داده مورد نیاز را تامین خواهد کرد ، استفاده می نماید .
خصلت Name ، نام در نظر گرفته شده برای پارامتر را که از آن در عبارت SELECT استفاده خواهد شد را مشخص می نماید .
خصلت ControlID ، شناسه (id ) کنترلی است که داده مورد نیاز برای پارامتر را مشخص می نماید .
PropertyName ، خصلت کنترلی است که از مقدار آن به عنوان مرجع استفاده می گردد ( در این مثال خصلت Text مربوط به کنترل TextBox ) .
در مثال فوق از یک پارامتر در عبارت SELECT استفاده شده است ، بنابراین به یک کنترل <asp:ControlParameter> نیاز می باشد. در صورتی که لازم است از چندین پارامتر استفاده شود ، می بایست برای هر یک از آنها از یک کنترل <asp:ControlParameter> استفاده گردد .
سادگی کد نویسی
با پارامتر درج شده در یک عبارت SELECT به عنوان یک مقدار داده literal برخورد می شود . بنابراین ، بر خلاف زمانی که از رشته های متصل شده به هم به منظور بکارگیری یک عبارت SQL استفاده می گردد ، احتمال درج داده مخرب بطرز مشهودی کاهش خواهد یافت . استفاده از پارامتر در عبارات SQL ، کاهش پیچیدگی کدینگ عبارات SQL را نیز به دنبال خواهد داشت .
کد زیر یک نمونه عبارت SQL را نشان می دهد که در آن از یک رشته متصل شده به هم استفاده شده است :
SQLString = "SELECT * FROM Books WHERE " & _
"BookType = '" & TypeTextBox.Text & "' AND " & _
"BookPrice > " & PriceTextBox.Text & " AND " & _
"BookQty <= " & QtyTextBox.Text & " AND " & _
"BookTitle LIKE '%" & TitleTextBox.Text & "%'"
کد فوق را می توان با عبارت زیر جایگزین نمود :
SQLString = SELECT * FROM Books WHERE " & _
"BookType = @BookType AND BookPrice > @BookPrice AND " & _
"BookQty <= @BookQty AND BookTitle LIKE @BookQty"
درون کنترل AcessDataSource ، می بایست از یک بخش SelectParameters به منظور معرفی کنترل هائی که مقدار مورد نیاز هر یک از پارامترها را تامین می نمایند ، استفاده گردد .
تهدیدات امنیتی در صورت عدم ارزیابی داده ورودی
برنامه های وب ، داده مورد نیاز خود را از طریق درخواست های مبتنی بر پروتکل HTTP دریافت می نمایند ( در برخی موارد ممکن است داده مورد نیاز یک برنامه وب از طریق یک فایل تامین گردد). با توجه به ماهیت پروتکل فوق ، مهاجمان می توانند هر بخشی از یک درخواست HTTP نظیر url ، querystring ، هدر ، کوکی ها ، فیلدهای موجود بر روی فرم و فیلدهای مخفی را تحریف تا ضمن نادیده گرفتن مکانیزم های امنیتی بکارگرفته شده در یک سایت ، آن را با مشکلات امنتیی متعددی مواجه نمایند. حملات forced browsing, command insertion, cross site scripting, buffer overflows, format string attacks و SQL injection نمونه هائی در این زمینه می باشند .
تعداد زیادی از برنامه های وب صرفا" از مکانیزم های سمت سرویس گیرنده به منظور بررسی و ارزیابی داده ورودی استفاده می نمایند . مهاجمان با استفاده از روش های متفاوتی می توانند مکانیزم های استفاده شده به منظور ارزیابی داده ورودی را نادیده گرفته و برنامه های وب را در مقابل داده ورودی مخرب خلع سلاح نمایند . مهاجمان ، بدین منظور می توانند با استفاده از ابزارهائی نظیر telnet درخواست های HTTP را تولید نمایند . بدیهی است در چنین مواردی نباید انتظار داشت آنان واکنش هائی را که مد نظر پیاده کنندگان برنامه های وب در سمت سرویس گیرنده است ، انجام دهند . با این که بررسی و ارزیابی داده ورودی در سمت سرویس گیرنده یک ایده عالی است و می تواند به عنوان یک اقدام مناسب در جهت افزایش کارآئی برنامه های وب تلقی گردد ولی قطعا" رویکرد فوق دارای مزیت امنیتی خاصی نخواهد بود .
به منظور ارزیابی داده ورودی می بایست از روش های سمت سرویس دهنده استفاده گردد تا یک لایه دفاعی مناسب به منظور پیشگیری از درج داده مخرب توسط مهاجمان ایجاد گردد . پس از تحقق خواسته فوق ، می توان با دقت اقدام به بهینه سازی روش های استفاده شده به منظور بررسی و ارزیابی داده ورودی در سمت سرویس گیرنده نیز نمود تا ترافیک غیرضروری بر روی سرویس دهنده به حداقل مقدار ممکن برسد .
بررسی یک نمونه
در برخی موارد از داده ورودی در یک TextBox به منظور ایجاد یک query در ارتباط با یک بانک اطلاعاتی استفاده می گردد . روش فوق ، ممکن است مسائل و مشکلات امنیتی متعددی را به دنبال داشته باشد ( از عدم اجرای اسکریپت ها گرفته تا بروز اشکال در بانک اطلاعاتی ) . مجددا" لازم است به این نکته مهم اشاره گردد که کنترل های validation ، به منزله اولین لایه دفاعی در مقابل درج داده مخرب محسوب می گردند و این اطمینان را ایجاد می نمایند که صرفا" داده معتبر در اختیار سایر لایه های یک برنامه خصوصا" لایه داده آن قرار داده خواهد شد .
مهاجمان می توانند از طریق TextBox استفاده شده بر روی یک فرم ، کدهای مخربی را به سیستم وارد نمایند که حذف تمامی بانک اطلاعاتی را به دنبال داشته باشد . با این که همواره فرض پیاده کنندگان برنامه های وب بر این است که از TextBox برای درج داده در سیستم استفاده خواهد شد ، ولی واقعیت این است که ممکن است از آنها برای درج کد نیز استفاده گردد . SQL injection یک نمونه از تهدیدات موجود در این زمینه است .
SQL Injection
فرض کنید از یک TextBox برای درج داده بر روی یک فرم استفاده شده باشد و پس از درج داده توسط کاربر ، از آن به منظور بازیابی رکوردهائی خاص از یک بانک اطلاعاتی استفاده می گردد . بدین منظور ، از دستور SELECT به صورت زیر استفاده شده است :
SQLString = "SELECT * FROM MyTable WHERE MyKey = '" & MyTextBox.Text & "'"
دستور SELECT ، به صورت پویا از مقدار درج شده در TextBox استفاده می نماید . ظاهرا" همه چیز درست است و مشکل خاصی وجود نخواهد داشت ولی فرض کنید کاربری کد SQL زیر را در TextBox وارد نماید :
Search :
پس از درج داده فوق در TextBox ، وضعیت query نوشته شده در برنامه به صورت زیر خواهد بود :
SELECT * FROM MyTable WHERE MyKey = ' ' ; DROP DATABASE MyDatabase
در چنین مواردی ، عبارت SQL شامل دو دستور مجزاء می گردد که اولین دستور آن با توجه به ماهیت داده ورودی مقدار null خواهد بود و عملا" رکوردی را برنمی گرداند و دومین عبارت SQL ، باعث حذف یک بانک اطلاعاتی خواهد شد . بدین ترتیب یک SQL injection محقق می گردد و کد مخرب با داده مورد انتظار در عبارت SQL جایگزین می شود. با این که در یک بانک اطلاعاتی اکسس ، نمی توان چندین عبارت SQL را در یک خط استفاده نمود ولی برخی از سیستم های مدیریت بانک های اطلاعاتی قادر به اجراء کد فوق خواهند بود .
پیاده کنندگان برنامه های وب می توانند از کنترل های validation به منظور بلاک نمودن اینچنین کدهائی استفاده نمایند . بدین منظور می توان طول رشته ورودی ، نوع داده ورودی و یا وجود داده ورودی در یک محدوده خاص را بررسی نمود . تست های فوق در مواردی که داده ورودی از نوع string و با طول نامشخص باشند ، کارساز نبوده و نمی توان از کنترل های اشاره شده در جهت ایجاد یک سطح حفاظتی مناسب استفاده نمود .
راه حل چیست ؟
بهترین روش برای حفاظت در مقابل ورود کدهای مخرب به سیستم ، استفاده از عبارات SQL به صورت پارامتریک در مقابل بکارگیری مستقیم داده ورودی است . پارامترها ، مکان لازم برای نگهداری مقادیر داده را فراهم نموده و این اطمینان را ایجاد می نمایند که از مقادیر ورودی مستقیما" در کد استفاده نخواهد شد .
در کد زیر از یک عبارت SELECT به منظور بازیابی رکوردهائی خاص از جدول Books در بانک اطلاعاتی BooksDB استفاده شده است . عبارت SQL به عنوان خصلت SelectCommand کنترل منبع داده AccessDataSource ( با " id="BookSource ) در نظر گرفته شده است .
Sub Get_Record (Src As Object, Args As EventArgs)
Dim SQLString As String
SQLString = "SELECT BookID, BookTitle, BookPrice FROM Books" & _
"WHERE BookID = @BookID"
BookSource.SelectCommand = SQLString
End Sub
یک پارامتر با استفاده از نام خود که به دنبال یک کاراکتر "@" می آید ( در این مثال BookID @ ) ، مشخص می گردد و یک مرجع به داده ورودی است که در عبارت SELECT و به منظور بازیابی رکوردهای مورد نظر استفاده می گردد . فرض کنید ، کاربر داده زیر را در TextBox وارد نماید :
Book ID :
مقدار ورودی در TextBox ، به عنوان مقدار پارامتر BookID @ در عبارت SELECT در نظر گرفته می شود . در چنین مواردی ، می بایست با صراحت مقدار درج شده در TextBox را با پارامتر فوق مرتبط نمود . زمانی که از کنترل AccessDataSource به منظور بازیابی داده از یک بانک اطلاعاتی استفاده می گردد ، برای مشخص کردن پارامترهای مورد نیاز در یک عبارت SELECT ، می بایست از بخش <SelectParameters> در کنترل استفاده گردد . در این بخش می توان از یک و یا چندین کنترل <asp:ControlParameter> استفاده نمود . با استفاده از کنترل <asp:ControlParameter> ، می بایست یک نام را برای پارامتر در نظر گرفت .همچنین ، لازم است کنترلی که قرار است مقدار آن به عنوان پارامتر در نظر گرفته شود نیز مشخص گردد.
کد زیر نحوه استفاده از پارامتر BookID @ در کنترل AccessDataSource را نشان می دهد .
Book ID:
<asp:TextBox id="BookIDInput" Runat="Server"/>
<asp:Button Text="Find" OnClick="Get_Record" Runat="Server"/>
<asp:AccessDataSource id="MySource" Runat="Server" DataFile="../DB/BooksDB.mdb">
<SelectParameters>
<asp:ControlParameter Name="BookID" ControlID="BookIDInput" PropertyName="Text"/>
</SelectParameters>
</asp:AccessDataSource>
توضیحات :
کنترل <asp:ControlParameter> از سه خصلت به منظور ایجاد ارتباط با کنترلی که داده مورد نیاز را تامین خواهد کرد ، استفاده می نماید .
خصلت Name ، نام در نظر گرفته شده برای پارامتر را که از آن در عبارت SELECT استفاده خواهد شد را مشخص می نماید .
خصلت ControlID ، شناسه (id ) کنترلی است که داده مورد نیاز برای پارامتر را مشخص می نماید .
PropertyName ، خصلت کنترلی است که از مقدار آن به عنوان مرجع استفاده می گردد ( در این مثال خصلت Text مربوط به کنترل TextBox ) .
در مثال فوق از یک پارامتر در عبارت SELECT استفاده شده است ، بنابراین به یک کنترل <asp:ControlParameter> نیاز می باشد. در صورتی که لازم است از چندین پارامتر استفاده شود ، می بایست برای هر یک از آنها از یک کنترل <asp:ControlParameter> استفاده گردد .
سادگی کد نویسی
با پارامتر درج شده در یک عبارت SELECT به عنوان یک مقدار داده literal برخورد می شود . بنابراین ، بر خلاف زمانی که از رشته های متصل شده به هم به منظور بکارگیری یک عبارت SQL استفاده می گردد ، احتمال درج داده مخرب بطرز مشهودی کاهش خواهد یافت . استفاده از پارامتر در عبارات SQL ، کاهش پیچیدگی کدینگ عبارات SQL را نیز به دنبال خواهد داشت .
کد زیر یک نمونه عبارت SQL را نشان می دهد که در آن از یک رشته متصل شده به هم استفاده شده است :
SQLString = "SELECT * FROM Books WHERE " & _
"BookType = '" & TypeTextBox.Text & "' AND " & _
"BookPrice > " & PriceTextBox.Text & " AND " & _
"BookQty <= " & QtyTextBox.Text & " AND " & _
"BookTitle LIKE '%" & TitleTextBox.Text & "%'"
کد فوق را می توان با عبارت زیر جایگزین نمود :
SQLString = SELECT * FROM Books WHERE " & _
"BookType = @BookType AND BookPrice > @BookPrice AND " & _
"BookQty <= @BookQty AND BookTitle LIKE @BookQty"
درون کنترل AcessDataSource ، می بایست از یک بخش SelectParameters به منظور معرفی کنترل هائی که مقدار مورد نیاز هر یک از پارامترها را تامین می نمایند ، استفاده گردد .