سردبیر: مطلبی که در ادامه میخوانید یک ترجمه آزاد از مقاله معروف DOM Based Cross Site Scripting or XSS of the Third Kind است. اگرچه آخرین ویرایش مقاله مذکور مربوط به سال ۲۰۰۵ هست و چیزی حدود ۱۰ سال از انتشار آن گذشته است، برای مثال در این مقاله اثری از مرورگر chrome به چشم نمیآید، چون این مرورگر ۳ سال بعد از انتشار این مطلب متولد شده است. اما با همه اینها مطلب هنوز هم به عنوان مرجع برخی مقالات معتبر استفاده میشود.
چکیده
همهی ما میدانیم که XSS چیست؛ درست است؟ این آسیبپذیری زمانی رخ میدهد که دادههای مخرب ارسالی (عموما درون صفحهی HTML همراه با کدهای جاوااسکریپت) به برنامه بازگردانده شده و جزو محتوای HTML چاپ شود که در این صورت، این چاپشدن به معنای اجرای کدهای جاوااسکریپت نیز خواهد بود. خوب، این موضوع غلط است. این موضوع حملهی XSS هست، اما کامل نبوده و نقص آن، مطلبی است که در این مقاله آوردهام. این موضوعها حداقل در برخی از مبانی با همدیگر یکسان نیستند.
حملهی XSS توصیفشده در بالا از نوع ناپایدار/بازتابی/reflected میباشد (مثالی از آن دادههای مخربی است که به یک صفحه چسانده شده (embedded) و بلافاصله توسط مرورگر و بعد از درخواست بازگردانده میشود.) یا از نوع پایدار/ذخیرهشده/stored است که در آن دادههای مخرب در زمان دیگری بازگردانده میشود. اما نوع سومی از حملات XSS نیز وجود دارد که در وهلهی اول مبتنی بر ارسال دادههای مخرب به سرور نیست! ممکن است بگویید این تعریف با آنچه که از قبل میدانستیم در تناقض است. از لحاظ فنی این حملات نوع سومی از XSSاند که با نام DOM-Based XSS نیز شناخته میشوند. این مدل جدید از حمله، به خودی خود بحث جدیدی نیست و در واقع تا حدودی اختراع این روش، نتیجهی توجه به جنبهها و چاشنیهای مختلفی است که البته بسیار جذاب و مهماند.
توسعهدهندگان و برنامهنویسان برنامهها باید نسبت به DOM Based XSS شناخت پیدا کنند. چرا که این حمله به عنوان تهدیدی برای برنامههای تحت وب شناخته شده و شرایط به وجود آمدن آن با XSS استاندارد متفاوت است. در حال حاضر (سال ۲۰۰۵) تعداد بسیار زیادی از برنامههای تحت وب نسبت به حمله ی DOM-Based XSS آسیبپذیرند و این درحالی است که این صفحات در مقابل سایر حملات استاندارد XSS آسیبپذیر نیستند.
توسعهدهندگان، پشتیبانان سایتها و حتی افرادی که سایتها را از لحاظ امنیتی بازبینی میکنند میبایست با روشهای تشخیص آسیبپذیری DOM-برBased XSS و روشهای مقابله با آن آشنا باشند.
مقدمه
فرض بر این است که خوانندگان با XSSهای پایهای آشنایی دارند. XSS عموما به دو دستهی پایدار/persistent/stored و ناپایدار/reflected/non-persistent تقسیمبندی میشود. ناپایدار به این معناست که کدهای جاوااسکریپت مخرب، به محض دریافت یک درخواست http از سمت قربانی، response یا پاسخ http مربوط به آن را توسط سرور چاپ و اجرا می کند. پایدار نیز به معنای آن است که بارگذاری کد در سیستم (سرور) ذخیره شده و ممکن است بعدا در صفحهی آسیبپذیری که به قربانی ارائه میشود، آن کدها نیز الصاق شدهباشند.
همانگونه که در چکیده هم عنوان شد، مبنای این نوع از دستهبندی، بر اساس دادههای مخربی است که به سرور ارسال میشوند؛ در نوع اول، این دادهها در زمان دیگری به کاربر برگردانده میشود (پایدار) و در نوع دوم این اتفاق بلافاصله بعد از ارسال به سرور رخ میدهد (ناپایدار) اما این مقاله فراتر از این دسته بندی عمل است.
اگرچه در خصوص دستهبندی ارائهشده مثالهای نقض زیادی وجود ندارد اما شناخت تنها حملهی XSSای که بر بارگذاری یا همان payload الصاق شده به سرور تکیه نمیکند موضوع مهمی بوده و در شناسایی و روشهای جلوگیری نقش بسیار بسزایی خواهد داشت.
نمونه و بحث
قبل از توصیف یک سناریوی اولیه و بنیادی، تاکید بر این نکته مهم است که تکنیکهایی که در اینجا از آن ها استفاده میکنیم قبلا نیز به صورت عمومی منتشر شدهاست. بنابراین تکنیکهای استفادهشده مورد جدیدی نخواهد بود (هرچند ممکن است بعضی از آن ها جدید به نظر آید.).
پیشنیازی که برای یک سایت آسیبپذیر لازم است، صفحه ی HTMLای است که از دادههای document.location یا document.URL یا document.referrer به روشی غیر امن، استفاده نماید (یا هر نوع دیگری که هکر بتواند روی آن تاثیر بگذارد.).
قابل توجه خوانندگانی که با این نوع از اشیاء جاوااسکریپت آشنایی ندارند: زمانی که جاوااسکریپت در مرورگر اجرا میشود، مرورگر کد جاوااسکریپت را با شیهای مختلف که به عنوان DOM یا Document Object Model ارائه میشود، آماده میکند. شیء document سایر شیءها را مدیریت کرده و به واسطهی آن، اکثر خواص و propertyهای صفحه در زمان درخواست مرورگر ساخته میشوند. شی document از زیر-اشیاء (sub-object) دیگری (URL,Location,referrer)ساخته شده و تمام این موارد در سمت مرورگر میباشند (این نکته ی مهمی است که بعدا به آن خواهیم پرداخت).
بنابراین document.URL و document.location نزد مرورگر به عنوان URL صفحات شناخته میشوند. توجه کنید که این اشیاء جزیی از قسمت body در html نبوده و مرورگر آنها را چاپ نمیکند. شی document شامل شی body (که از آن برای نمایش محتوای پارس شده در html استفاده میشود) نمیشود.
استفاده از این نوع از کدهای جاوااسکریپتی که عبارت مربوط به URL را (با استفاده از document.URL یا document.location) پارس میکنند در صفحات HTML رایج بوده و به وسیلهی آن بعضی از کدهای سمت کلاینت اجرا میشوند. در زیر مثالی از آن را مشاهده مینمایید.
فرض کنید که مثال زیر محتوای صفحهی http://www.vulnerable.site/welcome.html باشد:
<HTML> <TITLE>Welcome!</TITLE> Hi <SCRIPT> var pos=document.URL.indexOf("name=")+5; document.write(document.URL.substring(pos,document.URL.length)); </SCRIPT> <BR> Welcome to our system … </HTML>
در شرایط عادی استفاده از این صفحه برای خوشآمدگویی به کاربر بوده و نحوهی استفاده از آن به شکل زیر است:
http://www.vulnerable.site/welcome.html?name=Joe
اما درخواستی مشابه زیر باعث پیادهسازی حملهی XSS میشود:
http://www.vulnerable.site/welcome.html?name=<script>alert(document.cookie)</script>
اما چرا؟ زمانی که مرورگر قربانی این لینک را دریافت میکند، یک درخواست از نوع HTTP به www.vulnerable.site ارسال شده و مرورگر صفحهی HTML بالایی (از نوع استاتیک!) را دریافت میکند. بعد از آن مرورگر قربانی شروع به پارس کردن (parsing) این HTML به DOM می کند. از طرفی DOM دارای شیای به نام document بوده که دارای یک ویژگی (property) به نام URL است و این ویژگی در ارتباط با URL صفحهی جاری برای ساخت بخشی از DOM مورد استفاده قرار میگیرد. وقتی این پارسر به کد جاوااسکریپت میرسد، آن را اجرا کرده و HTML خام این صفحه را دستکاری میکند. در نهایت، کد به document.URL ارجاع داده شده و بنابراین قسمتی از این رشته در زمان پارس به HTML الصاق (embedded) خواهد شد. این مورد فورا پارس شده و کد جاوااسکریپت به ((…)alert) میرسد و آن را به عنوان محتوای همان صفحه اجرا خواهد کرد.
بنابراین در این مثال شرایط XSS به وقوع پیوسته است.
نکات
۱. قسمت مربوط به کدهای مخرب (payload) در هیچ زمانی در درون صفحهی خام html الصاق (embedded) نمیشود. (بر خلاف انواع دیگر XSS)
۲. این اکسپلوییت تنها زمانی کار میکند که مرورگر کارکترهای URL را دستکاری نکند. موزیلا به صورت خودکار کارکترهای > و < موجود در document.URL را زمانی که URL به صورت مستقیم در نوار آدرس وارد نشود به ۳C% و ۳E% تبدیل کرده و بنابراین آسیبپذیری موجود در این روش به این شکل قابل اکسپلویت نخواهد بود. این مورد زمانی آسیبپذیر خواهد بود که در حمله، نیازی به > و < (در شکل خام) نباشد.
البته الصاقکردن (embedded) به صورت مستقیم در html تنها یکی از روشهای حمله است و سناریوهای مختلفی از حمله وجود دارند که در آنها نیازی به > و < نیست که در این صورت موزیلا نیز به صورت عمومی در برابر این حمله آسیبپذیر خواهد بود.
گریز از روشهای استاندارد جلوگیری و تشخیص
در مثال بالا قسمت payload از طریق کوئری مربوط به درخواست HTTP به سرور ارسال شده و ممکن است راه شناسایی آن مشابه سایر حملات XSS باشد. حملهی زیر را ملاحظه فرمایید:
http://www.vulnerable.site/welcome.html#name=<script>alert(document.cookie)<script>
به علامت عدد (number sign یا #) که بعد از نام فایل میآید دقت کنید. این علامت به مرورگر میگوید که تمام چیزهایی که بعد از آن میآید یک قطعه (fragment) بوده و بخشی از درخواستِ ارسالی به سرور نخواهد بود. اینترنت اکسپلورر و موزیلا این قطعات را به سرور ارسال نکرده و بنابراین سرور تنها www.vulnerable.site/welcome.html را دیده و قسمت payload توسط سرور قابل رویت نیست. همانگونه که میبینیم این تکنیک یکی از روشهای اصلی برای عدم ارسال دادههای مخرب به سرور است.
در برخی اوقات امکان مخفیسازی payload غیر ممکن است. برای مثال زمانی که payload مخرب، مربوط به قسمتی از نام کاربری باشد نمیتوان آن را به روشهای معمول مخفی ساخت. (مثل URLای شبیه http://username@host.) در این گونه موارد، مرورگر یک درخواست با هدرهای اعتبارسنجی شامل نام کاربری (که حاوی payload مخرب است) را تولید کرده و بنابراین قسمت payload نیز به سرور ارسال میشود. (به روش کدگذاری Base64 -بنابراین در اینگونه از موارد IDS/IPS میبایست ابتدا دادهها را به منظور شناسایی حمله از کدگذاری خارج کند.)
مسلما در شرایطی که امکان مخفیسازی payload به صورت کامل وجود دارد راههای شناسایی و جلوگیری آنلاین مثل IDS و IPS و فایروالهای برنامههای تحت وب، کارساز نبوده و حتی در مواقعی که payload به سرور ارسال میشود نیز راههای زیادی برای جلوگیری از تشخیص وجود دارد.
برای مثال حتی اگر از پارامتری به صورت خاص محافظت شود (مثل پارامتر name در مثال بالا) باز هم امکان موفقیتآمیز بودن حمله وجود دارد:
http://www.vulnerable.site/welcome.html?notname=<script>(document.cookie)</script>
بنابراین برای جلوگیری از حقهی استفاده از #، نیازمند محدودیتهای بیشتری در سیاستهای امنیتی در پارامتر ارسالی name میباشیم. فرض کنید مقدار زیر را به سرور ارسال کنیم:
http://www.vulnerable.site/welcome.html?notname= <script>alert(document.cookie)<script>&name=Joe
در شرایطی که سیاستهای امنیتی نامهای اضافی در پارامترها را محدود کرده باشد عبارتی مثل foobar میبایست در ابتدا آمده و مقدار آن شامل payload مورد نظر باشد:
http://www.vulnerable.site/welcome.html?foobar=name=<script>alert(document.cookie)<script>&name=Joe
طبق سناریوی موجود در این لینک در صورت نوشتهشدن تمام document.location در صفحه html، کار هکر بسیار راحت خواهد بود (کد جاوااسکریپت با هدف پیدا کردن نام پارامترهای مشخصی پویش نشود). با این کار هکر میتواند به صورت کامل payload مربوط به حمله را با ارسالی به شکل زیر مخفی نماید:
/attachment.cgi?id=&action=foobar#<script>alert(document.cookie)</script>
حتی در شرایط بازبینی payload توسط سرور، تنها زمانی سیستم محافظتی جواب میدهد که درخواست ارسالشده به صورت کامل نادیده و یا پاسخ با متنی حاوی پیام خطا جایگزین شود.
در منابع شماره [۵] و [۶] را مجددا مشاهده فرمایید. اگر هدر اعتبارسنجی به سادگی توسط یک سیستم محافظتی میانی حذف شود، هیچ تاثیری روی مقدار بازگرداندهشده توسط صفحهی اصلی، وجود نخواهد داشت. همچنین هر گونه تلاش جهت پاکسازی دادهها روی سرور (چه به وسیلهی پاک کردن کارکترهای مخرب و چه به وسیله ی کد کردن آنها) میتواند در برابر این حمله بی اثر باشد.
در خصوص document.referrer نیز مقدار payload از طریق هدر Referrer به سرور ارسال میشود. البته در صورتی که مرورگر یا یک دستگاه میانی، مقدار این هدر را پاک کند، هیچگونه راهی برای پیدا کردن و دنبال کردن حمله وجود نداشته و به صورت کامل غیر قابل تشخیص میشود. روشهای سنتی برای این کار عبارتند از:
- استفاده از کدینگ html برای دادههای خروجی در سمت سرور
- پاک کردن/کدینگ دادههای ورودی مخرب در سمت سرور
که البته در برابر حملات DOM-Based XSS کارساز نخواهد بود!
با توجه به اینکه اسکنرهای آسیب پذیری، از طریق تزریق و اینجکتهای اشتباه (که گاهی از آن با نام فازبندی یا fuzzing یاد میشود) و بر اساس مقادیری که به صفحه بازگردانده می/نمیشود خروجی را ارزیابی کرده و به نتیجه میرسند، اینگونه محصولات در خصوص این نوع از حمله مفید نخواهد بود. (برای این کار ابتدا یک سری کد را در سمت کلاینت و در مرورگر اجرا و تاثیرات آن در زمان اجرا را مشاهده میکنند)
البته اگر برنامه بتواند جاوااسکریپتهای پیدا شده در یک صفحه را به صورت استاتیک آنالیز کند، ممکن است به الگوهای مشکوکی دست یابد. همچنین اگر برنامه خودش جاوااسکریپتی را اجرا کند (و به درستی روی اشیاء DOM تاثیر بگذارد) و یا از اجراهایی مشابه آن بهره ببرد ممکن است بتوانیم حمله را تشخیص دهیم.
با توجه به اینکه مرورگرها کدهای جاوااسکریپت را در سمت کلاینت اجرا میکنند، اسکنرهای دستی که از مرورگر استفاده مینمایند میتوانند در تشخیص این نوع از آسیبپذیری کار آمد باشد. هرچند ممکن است محصولاتی وجود داشته باشند که محیطی مشابه مرورگر را شبیهسازی کرده و کدهای جاوااسکریپت را در آن محیطها مورد وارسی قرار دهند.
راههای دفاعی موثر
- از بازنویسی مستندات، ریدایرکتشدن یا سایر اقدامات حساس که با استفاده از دادههای حساس در سمت کاربر صورت میپذیرد، جلوگیری کنید. بسیاری از این کارها را میتوان با استفاده از صفحات پویا و در سمت سرور انجام داد.
- کدهای (جاوااسکریپت) سمت کاربر را به دقت آنالیز کنید. ارجاعاتی که به اشیاء DOM میشود و امکان تاثیرگذاری روی آن توسط کاربر (هکر) وجود دارد میبایست به صورت جدی مورد بازرسی قرار گیرد و این بازرسی شامل موارد زیر میشود (البته به این موارد محدود نمیشود.):
- document.URL
- document.URLUnencoded
- document.location (and many of its properties)
- document.referrer
- window.location (and many of its properties)
توجه داشته باشید که شی document، شی windows و سایر مشتقات آنها ممکن است به صورتهای مختلف مورد ارجاع قرار گیرند. مثل windows.location،ا location و یا با استفاده از یک هندلکننده به یک windows و استفاده از آن (برای مثال handle_to_some_window.location )
توجه ویژهای به سناریوهای مختلفی که به وسیلهی آن DOM مورد دستکاری و تغییر قرار می گیرد داشته باشید. این سناریوها شامل روشهای مستقیم، دسترسی از طریق HTML خام، دسترسی مستقیم به DOM و … میشوند. برای مثال
- Write raw HTML, e.g.:
- document.write(…)
- document.writeln(…)
- document.body.innerHtml=…
- Directly modifying the DOM (including DHTML events), e.g.:
- document.forms[0].action=… (and various other collections)
- document.attachEvent(…)
- document.create…(…)
- document.execCommand(…)
- document.body. … (accessing the DOM through the body object)
- window.attachEvent(…)
- Replacing the document URL, e.g.:
- document.location=… (and assigning to location’s href, host and hostname)
- document.location.hostname=…
- document.location.replace(…)
- document.location.assign(…)
- document.URL=…
- window.navigate(…)
- Opening/modifying a window, e.g.:
- document.open(…)
- window.open(…)
- window.location.href=… (and assigning to location’s href, host and hostname)
- Directly executing script, e.g.:
- eval(…)
- window.execScript(…)
- window.setInterval(…)
- window.setTimeout(…)
در تکمیل مثال بالا، یک راه دفاعی کارساز و موثر این است که قسمتی از اسکریپت اصلی را با کدی که در ادامه آمده است، جایگزین نماییم. در این کد، رشتهای که قرار است در صفحه ی HTML نوشته شود را چک می کند تا تنها از حروف الفبا و اعداد تشکیل شده باشد:
<SCRIPT> var pos=document.URL.indexOf("name=")+5; var name=document.URL.substring(pos,document.URL.length); if (name.match(/^[a-zA-Z0-9]$/)) { document.write(name); } else { window.alert("Security error"); } </SCRIPT>
برای این توابع میتوانید (میبایست) از کتابخانههای عمومی که برای پاکسازی دادهها وجود دارد، استفاده کنید (برای مثال از مجموعهای از توابع جاوااسکریپت که کار اعتبارسنجی ورودیها و پاکسازی را انجام می دهند.).
سطح پایینتری از اقدامات محافظتی این است که در برابر هکر قوانین امنیتی ارائه داده و آن را در کدهای HTML الصاق کنید. فهم این موضوع آسانتر بوده و حمله را نیز آسانتر میکند! در مثال بالا، شرایط بسیار ساده بوده و در سناریوهای پیچیدهتر نیز ممکن است مفید باشد.
۳. به کارگیری سیاستهای بسیار محدودکننده به وسیلهی IPS. برای مثال صفحه ی welcome.html میبایست تنها یک پارامتر به نام name را دریافت کند که به این منظور میبایست محتویات را چک نمود. همچنین در صورت بروز هرگونه مورد غیر مجاز (شامل پارامترهای بیشتر و یا بدون پارامتر) نباید صفحهی اصلی را ارائه کرد. همچنین هر کار غیر مجاز دیگر (شامل هدر Authorization یا هدر Referrer با محتوایی مخرب) میبایست به عدم ارائهی صفحهی اصلی بینجامد. البته حتی با انجام این کارها نیز نمیتوان تضمین کرد که این حمله خنثی خواهد شد.
توضیحی در خصوص آسیبپذیری ریدایرکت
بحث بالا در خصوص XSS است. در حالی که خیلی از حملات به این شکل صورت میپذیرد که تنها با استفاده از اسکریپتهای سمت کاربر، مرورگر به صورت نا امن به محل دیگری که آسیبپذیر است ریدایرکت خواهد شد.
در این گونه از موارد نیز تکنیکها و ملاحظات بالا کماکان برقرار است.
نتیجهگیری
از آنجایی که حملات XSS به صورت عمومی اینگونه توصیف میشوند: «سرور به صورت فیزیکی دادههای کاربر را درون صفحات پاسخ یا response در html الصاق میکند.»، باید دانست که نوع دیگری از حملات XSS نیز وجود دارد که تکیهی آن به الصاق دادهها در سمت سرور نیست.
این موضوع زمانی اهمیت دارد که بخواهیم در خصوص راههای تشخیص و جلوگیری از XSS بحث کنیم. در حال حاضر تکنیکهایی که به صورت عمومی مورد بحث است تنها به دادههایی که توسط ورودیهای مخرب کاربر توسط سرور دریافت و در درون صفحات HTML الصاق میشوند، میپردازد. که در این صورت، تکنیکهایی که هم اکنون مورد استفاده قرار میگیرند در تشخیص و جلوگیری از حملاتی که در این مقاله مورد بحث قرار گرفت، ناکارآمد خواهند بود.
تقسیمبندی حملات XSSای که بر پایهی دادههای الصاقی کاربر در سمت سرور تکیه دارند در دو نوع قرار میگیرند: یکی ناپایدار (non-persistent) یا بازتابی (reflected) و نوع بعدی پایدار (persistent) یا ذخیرهشده (stored). به همین دلیل نوع سومی از XSS پیشنهاد میشود که تکیهی آن بر الصاقات سمت سرور نباشد و نام آن را “DOM Based XSS” میگذاریم.
در زیر مقایسهای بین XSS استاندارد و DOM Based XSS را مشاهده میفرمایید:
XSS استاندارد | DOM Based XSS | |
علت اصلی | الصاق نا امن ورودیهای کاربری در صفحات html به صورت خارج از محدوده | عدم کنترل ارجاعات نا امن و استفاده از آن (در کدهای سمت کلاینت) به شیهای DOM در سروری که صفحات را فراهم کرده است. |
مالک | برنامهنویسان وب (CGI) | برنامهنویسان وب (HTML) |
نوع صفحات | تنها داینامیک و پویا (اسکریپت CGI) | عموما استاتیک (HTML) البته همیشه اینگونه نیست. |
تشخیص آسیب پذیری |
|
|
تشخیص حمله |
|
اگر تکنیکهای گریز قابل اجرا و استفاده باشد، هیچ راهی برای تشخیص وجود ندارد. |
راه های دفاعی موثر |
|
|
منابع
توجه داشته باشید که URLهایی که در زیر آمده در زمان نوشتن این مقاله (۴ جولای ۲۰۰۵) فعال بوده و ممکن است در حال حاضر وجود نداشته باشد. برخی از این موارد به صورت مستندات در زمان نوشتن این مقاله بودهاند و ممکن است بعد از نوشتهشدن این مقاله، به روز و اصلاح شوند.
درباره نویسنده
Amit Klein به عنوان یک محقق امنیتی برنامههای تحت وب شناخته میشود. آقای کلین دارای مقالات تحقیقی مختلفی در خصوص تکنولوژیهای مختلف در برنامههای تحت وب –از HTTP گرفته تا XML، SOAP و وبسرویسها — است. ایشان عناوین مختلفی را مورد بررسی قرار داده است، از جمله قاچاق درخواستهای HTTP، ایندکسگذاری به صورت نا امن، تزریق XPath به صورت کور (blind)، تکهتکهسازی پاسخهای HTTP، ایمنسازی برنامههای تحت وب NET.، مسمومسازی کوکیها، XSS و غیره. کارهای وی در مجلهی Dr. Dobb، نشریهی SC، مجلهی ISSA و مجله ی IT Audit منتشر و در کنفرانس های CERT و SANS ارائه و در منابع و سرفصلهای مختلف آکادمیک از آن استفاده شدهاست.
آقای کلین عضوی از WASC است. (Web Application Security Consortium یا کنسرسیوم امنیت برنامه های تحت وب)
لینک مقاله: