یدا
این مقاله مروری است بر رایج ترین راه های مقابله با حملات XSS در برنامه های تحت وب که با بررسی روش های مطرح شده در حیطه برنامه نویسی تحت وب و با بهره گیری از رهنمودهای استاد گرانقدر جناب آقای کاویانی تهیه شده و خدمت دوستان محترم تقدیم می گردد.
امروزه یکی از مهم ترین دغدغه های توسعه دهندگان برنامه های تحت وب بالا بردن سطح امنیت برنامه ها برای جلوگیری از نفوذ کاربران مهاجم و دسترسی احتمالی آن ها به اطلاعات محرمانه و کلیدی می باشد. یکی از رایج ترین انواع حملاتی که همواره این برنامه ها را در معرض خطر قرار می دهند حملات Cross- site scripting یا XSS می باشند.
حملات XSS به حملاتی اتلاق می شود که در آن کاربر مهاجم از طریق تزریق (Injection ) کدهای JavaScript یا HTML ای به صفحات وب و از طریق حفره های امنیتی موجود در آن ها به این صفحات نفوذ کرده و به داده هایی چون اطلاعات کاربران و یا Cookie ها دست می یابد.
رایج ترین دلایلی که می توانند برنامه های کاربردی تحت وب را در برابر حملات XSS آسیب پذیر نمایند عبارتند از :
- عدم اعتبار سنجی ورودی های کاربران
- عدم کدگذاری اطلاعات خروجی
- اعتماد به داده های بازیابی شده از یک پایگاه داده
بررسی روش های مقابله با حملات XSS در ASP.NET :
برای محافظت برنامه ها در برابر حملات XSS شما باید فرض را بر این بگیرید که تمام اطلاعات ورودی می توانند مخرب باشند بنابراین باید تمام اطلاعات ورودی را اعتبار سنجی نموده و برای آن ها قید بگذارید.همچنین هر نوع اطلاعات خروجی که می تواند شامل کاراکترهای HTML ای باشد اعم از اطلاعات خوانده شده از فایل یا دیتابیس باید رمزگذاری گردد .
در ادامه به بررسی راههای جلوگیری از حملات Cross- site scripting در برنامه های تحت وب (َAnti-XSS) خواهیم پرداخت :
1- اعتبار سنجی ورودی های کاربران :
گام اول : بررسی اینکه آیا ASP.NET Request Validation فعال است یا خیر :
برای این کار کافی است که در فایل Web.config و در تگ < system.web > پراپرتی validateRequest از page را برابر True قرار دهید :
شما می توانید ValidateRequest را برای هر یک از صفحات به صورت جداگانه فعال و یا غیرفعال نمایید . بنابراین باید این ویژگی را در تمامی صفحات خود کنترل نمایید.
برای تست کردن این نوع از حملات کافی است که یک صفحه ASP.Net جدید ایجاد کرده سپس در صفحه aspx کدهای زیر را وارد نمایید :
<%@ Page Language="C#" ValidateRequest="false" %>
برنامه را اجرا کنید .خواهید دید که کد اسکریپت وارد شده به درستی اجرا شده و و پس از فشردن دکمه ی ثبت پیغام "hello " به شما نمایش داده می شود:
اکنون ValidateRequest را برابر True قرار دهید و برنامه را مجددا اجرا کنید .این بار با پیغام خطای زیر مواجه خواهید شد :
A potentially dangerous Request.Form value was detected from the client (txtString="<script>alert('hello...").
که این بدین معنی است که ASP.NET validation فعال بوده و از اجرای کدهای HTML ای مخرب جلوگیری
می نماید.
گام دوم: استفاده از Validator ها برای کنترل کردن ورودی ها ی کاربر:
علاوه بر چک کردن مقادیر ورودی از طریق کدهای سمت کاربر (client-side) لازم است که ورودی هایی که از کنترل های net . مانند TextBox گرفته می شوند نیز کنترل شوند . برای این کار ASP.NET ابزار مناسبی در اختیار برنامه نویسان وب قرار می دهد با نام Validator . در واقع Validator ها با گذاشتن قید روی ورودی ها از ورود داده های مخرب جلوگیری می نمایند.
این Validator ها عبارتند از:
- RegularExpressionValidator : برای کنترل ورودی هایی از نوع Text
- RangeValidator : برای کنترل کردن بازه های عددی ˛ زمانی ˛ رشته ای
- CustomValidator : برای کنترل اینکه مثلا آیا تاریخ ورودی قبل از یک تاریخ خاص قرار دارد و یا بعد از آن .
هر سه این Validator ها دارای پارامتر های مشترک زیر می باشند:
ControlToValidat : اشاره به شناسه کنترلی که قرار است مقدار آن ارزیابی شود می کند.
ErrorMessage : پیغام خطایی که در صورت معتبر نبودن مقدار ورودی به کاربر برگردانده خواهد شد.
در ادامه به عملکرد هریک از این Validator ها می پردازیم :
- اعتبار سنجی ورودی فیلدهای متنی (TextFields) از طریق RegularExpressionValidator :
به عنوان مثال می خواهیم ورودی کنترل TextBox ما فقط شامل کاراکترهای خاصی بوده ودر غیر اینصورت به کاربر پیغام خطا برگرداند:
برای این کار کافی است مقدار ValidationRequest را برابر عبارت معتبر مورد نظر قرار دهیم . در مثال بالا کنترل TextBox فقط حروف کوچک وبزرگ انگلیسی را به عنوان ورودی می پذیرد و در صورتیکه ورودی چیزی غیر از آن باشد پیغام "Invalid name " بر می گرداند.
- اعتبار سنجی ورودی فیلدهای عددی(Numeric Fields ) بااستفاده از RangeValidator :
در اکثر موارد مقادیر عددی باید از نظر نوع داده و یا بازه ای که در آن قرار می گیرند کنترل شوند . برای این منظور می توان از RangeValidator استفاده نمود .هم چنین از RangeValidator برای چک کردن انواع داده ای پول ˛ تاریخ ˛ اعشار و رشته ها نیز می توان استفاده کرد.
برای استفاده از این Validator کافی است که پارامترهای ControlToValidate ˛ Type ˛ MinimumValue ˛ MaximumValue و ErrorMessage را ست کنیم.
در مثال زیر بررسی می شود که مقدار ورودی rangeInput از نوع Integer و در بازه بین 0 تا 255 باشد و در غیر اینصورت پیغام خطا برگردانده شود.
- اعتبار سنجی ورودی ها از طریق CustomValidator :
گاهی ما نیاز داریم مثلا یک ورودی از نوع تاریخ با یک مبدا تاریخی خاص مثلا امروز مقایسه کنیم تا نتیجه بگیریم که این ورودی مربوط به گذشته است یا آینده . د رموارد این چنینی می توان از CustomValidator استفاده نمود . برای این منظور کافی است منطق مورد نظر برای مقایسه را در یک تابع قرار داده و سپس پارامتر OnServerValidate از Validator را برابر نام این تابع قرار دهیم .
مثال زیر تاریخ ورودی را با تاریخ امروز مقایسه کرده و کنترل می کند که این تاریخ حتما مربوط به آینده باشد و در غیر اینصورت پیغام خطا برمی گرداند.
<%@ Page Language="C#" %>
2- تولید خروجی معتبر :
در بخش هایی از برنامه های تحت وب برنامه نویس ناگزیر است تا مقادیری را به عنوان خروجی به کاربر نمایش دهد . این خروجی ها اگر شامل مقادیر ورودی گرفته شده از کاربر و یا اطلاعات بازیابی شده از پایگاه داده ای که بین چند برنامه کاربردی به اشتراک گذاشته شده است باشند می توانند برنامه را در معرض حملات XSS قرار دهند .
برای جلوگیری از این گونه حملات پیشنهاد می شود که مراحل زیر را طی نمایید:
گام اول : یافتن کدهایی که خروجی HTML تولید می کنند :
ASP.NET غالبا به دو طریق خروجی HTML ایجاد می کند :
Response.Write
<% =
کدهای خود را بررسی کرده و قسمت هایی را که خروجی از نوع HTML و یا URL تولید می نمایند مشخص کنید.
گام دوم : تعیین خروجی هایی که در برگیرنده پارامترهای ورودی می باشند :
قسمت هایی از کد را که در آن مقدار خروجی در برگیرنده پارامترهای ورودی است را تعیین نمایید . این پارامترها می توانند از منابع مختلفی خوانده شوند. لیست زیر فهرستی از رایج ترین منابع ورودی است:
- Form field ها :
مانند :
Response.Write(name.Text );
Response.Write(Request.Form["name"]);
- Query strings ها :
مانند :
Response.Write(Request.QueryString["username"]);
توجه : حتما مراقب داده هایی که از پایگاه داده های مشترک بین چند برنامه کاربردی خوانده می شوند باشید.
- اطلاعات بازیابی شده از پایگاه های داده :
مانند :
SqlDataReader reader = cmd.ExecuteReader();
Response.Write(reader.GetString(1));
- Cookie collection ها :
مانند :
Request.Cookies["name"].Values["name"]);
- متغیرهای Session and application :
مانند :
Response.Write(Session["name"]);
Response.Write(Application["name"]);
گام سوم : پیدا کردن تگ های HTML ای که به طور بالقوه می توانند خطرناک باشند :
برخی تگ های رایج HTML که به کاربر مهاجم امکان تزریق کدهای اسکریپتی را می دهند عبارتند از :
و یا می توان از تگ <style> برای این نوع حملات استفاده نمود:
بنابراین در برنامه خود جستجو کرده و تگ هایی را که مستعد سوء استفاده می باشند تعیین کنید.
گام چهارم : ایمن سازی خروجی ها :
پس از اینکه شما کدهای ASP.NET ای را که خروجی HTML تولید می کنند تعیین نمودید باید آن ها را در مقابل حملات XSS ایمن نمایید . برای این کار می توان از روش های زیر بهره گرفت :
• Using Microsoft AntiXSSLibrary
• Encode HTML output
• Encode URL output
- استفاده از کتابخانه Anti-XSS ارائه شده توسط شرکت Microsoft :
یکی از بهترین روش های ایمن سازی خروجی در صفحات وب استفاده از کتابخانه ای است که توسط شرکت مایکروسافت ارائه شده است و با نام AntiXSS شناخته می شود. این کتابخانه توابع رمزگذاری گوناگونی را در بر می گیرد که می توان از آن ها برای مقابله با حملات XSS استفاده نمود. بر خلاف اکثر روش های استاندارد کدگذاری استفاده شده در NET framework . که از یک لیست سیاه استفاده کرده و اعضای این لیست را فیلتر می کنند ˛ کتابخانه ی AntiXSS از یک لیست سفید استفاده می کند به این صورت که هر کاراکتری که خارج از این مجموعه باشد فیلتر خواهد شد .
دو روش برای استفاده از AntixssLibrary وجود دارد:
1- شما می توانید از AntiXss Encoder در کدنویسی استفاده نمایید .
مثلا controller code, View markup, Web Forms code behind و Web Forms markup
2- در صورت استفاده از NET framework4 . شما می توانید یک Default Encoder تعریف کنید تا ASP.NET هرجا که نیاز به رمزگذاری خروجی ها داشت از آن استفاده نماید . پیشنهاد می شود که AntiXSS به عنوان رمزگذار پیش فرض انتخاب گردد.
** نحوه استفاده از AntiXSSLibrary در برنامه هایNET . و استفاده از آن به عنوان default encoder به زودی در قالب مقاله ای دیگر ارائه خواهد شد.
علاوه بر استفاده از AntiXSSLibrary می توان از امکانات خود NET . نیز برای رمزگذاری مقادیر خروجی استفاده نمود :
- رمزگذاری خروجی HTML :
هنگامی که خروجی شما شامل کدهای HTML بوده و یا اطلاعات آن از منابعی چون ورودی کاربران ˛ پایگاه های داده و یا حتی یک فایل خوانده می شود بهتر است از HttpUtility.HtmlEncode برای رمزگذاری کد ها استفاده نمایید .
HtmlEncode کاراکترهایی را که در HTML دارای معنای خاصی می باشند تبدیل به متغیر های HTML ای می نماید که معادل همان کد می باشند. به عنوان مثال کاراکتر > تبدیل به < و کاراکتر " تبدیل به ". می شود . نکته جالب توجه اینکه کد رمزنگاری شده مرورگر را وادار به اجرای کد نمی نماید که این ویژگی موجب جلوگیری از تزریق XSS می شود .
در مثال زیر نحوه استفاده از این متد نمایش داده شده است :
Response.Write(HttpUtility.HtmlEncode(Request.Form["name"]));
هم چنین با اجرای تکه کد زیر خواهید دید که حتی در صورت وارد کردن کدهای مخرب به عنوان ورودی˛ برنامه در مقابل حمله ایمن بوده و آن را اجرا نخواهد کرد:
<%@ Page Language="C#" AutoEventWireup="true"%>
- رمزگذاری خروجی URL :
اگر رشته خروجی URL شما حاوی ورودی هایی از نوع HTML می باشد بهتر است که آن را با استفاده از متد HttpUtility.UrlEncode رمزگذاری نمایید تا مهاجمین امکان سوء استفاده از اطلاعات موجود در رشته URL خروجی ر ا پیدا نکنند :
Response.Write(HttpUtility.UrlEncode(urlString));
به امید اینکه مطالب ارائه شده در این مقاله برای دوستان مفید واقع شود.
با احترام
الهام حلوائی قدیمی