xss (یا همون cross site scripting) یکی از آسیب پذیری های رایج در وب اپلیکیشن هاست که به ما اجازه میده اسکریپت ها و کدهای مخرب تزریق کنیم و میشه برای اهداف مختلفی ازش استفاده کرد مثل دزدیدن کوکی ها، تغییر ظاهر صفحه، فیشینگ و ...
اما در حال حاضر تعداد زیادی از وب اپلیکیشن ها مکانیزم هایی برای جلوگیری از حملات xss پیاده سازی کردن، این فیلتر ها ورودی و خروجی کاربر ها که ممکنه xss باشه رو اسکن میکنن و از این نوع حملات جلوگیری میکنن
اما همونطور که میدونید هیچ چیز 100% امن نیست و فیلتر هایی که از اجرا شدن xss محافظت میکنن .
قابل بایپس کردن و دور زدنه ⚠️
برخی از روش های دور زدن xss filter :
کدگذاری HTML (HTML Entities)
اینجا کاراکترها با انتیتی های HTML نوشته میشن.
مثلاً:
< میشه <
> میشه >
" میشه "
یا حتی به صورت عددی:
< میشه <
مرورگر اینها رو قبل از نمایش، تبدیل میکنه به همون علامت اصلی.
انکودینگ URL
اینجا از % به همراه مقدار هگزادسیمال استفاده میشه.
مثلاً:
< میشه %3Cخیلی وقتها سرور اول اینها رو decode میکنه، بعد پردازش رو انجام میده.
> میشه %3E
" میشه %22
کدگذاری Hex
اینجا از بکاسلش و مقدار هگز استفاده میشه:
< میشه \x3c
> میشه \x3e
" میشه \x22
این مدل بیشتر توی کانتکستهای جاوااسکریپتی دیده میشه.
کدگذاری Unicode
نسخه پیشرفتهترش اینه:
< میشه \u003c
> میشه \u003e
" میشه \u0022
باز هم مرورگر یا موتور JS قبل از اجرا اینها رو به کاراکتر واقعی تبدیل میکنه.
مثال واقعی برای درک بیشتر:
فرض کنین یک وبلاگ داریم که در بخش کامنت اجازه ارسال نظر به کاربران میده و این وبلاگ یک فیلتر xss ساده داره که هر موقع رشته های زیر رو در ورودی ببینه ازشون جلوگیری میکنه :
<script>
<img
<div
<iframe
<svg>
ما اگر بخوایم با این پیلود xss تزریق کنیم جلوی ما رو میگیره :
<script>alert(1)</script>
در اینجا 4 حالت برای دور زدن این فیلتر و انجام حمله xss داریم :
حالت اول: فقط HTML encode
<script>alert(1)</script>
اگر فیلتر فقط دنبال <script> ساده باشه، ممکنه اینو نفهمه.
ولی اگه قبل از پردازش decode کنه؟ بازم گیر میافتی.
حالت دوم: URL encode
%3Cscript%3Ealert(1)%3C/script%3E
باز هم همون داستان. اگر قبلش decode بشه، لو میره.
حالت سوم: Hex
\x3cscript\x3ealert(1)\x3c/script\x3e
اگر فیلتر فقط متن ساده رو چک کنه، ممکنه اینو نبینه.
حالت چهارم:
Unicode
\u003cscript\u003ealert(1)\u003c/script\u003e
باز هم بستگی داره سیستم چه زمانی decode کنه.
میتونیم با یه روش بهتر و حرفه ای تر این فیلتر رو دور بزنیم :
ترکیبی و تو در تو (Nested Encoding)
اینجا قضیه جالب میشه.
بهجای اینکه کل رشته رو یکدست encode کنیم، بخشهای مختلف رو با روشهای مختلف رمز میکنن مثلاً :
%26#x6c;t;\x73cript>\u0061lert(1)%26#x6c;t;/\x73cript>
اینجا چه اتفاقی افتاده ؟
& با URL encode شده (%26)
حرف l با HTML hex entity نوشته شده (#x6c;)
حرف s با \x73
حرف a با \u0061
بقیه حروف ساده اومدن
آخرش هم دوباره ترکیبی encode شده
در نتیجه سروری که فقط یه مدل خاص رو چک کنه، ممکنه نتونه رشته واقعی رو تشخیص بده و به نوعی گیج بشه .
اینجاست که میفهمیم چرا فیلترهای مبتنی بر «جستجوی رشته» خیلی وقتها شکست میخورن.
راه کارهای مقابله با xss
خروجیسازی ایمن بر اساس context (Context-Aware Output Encoding)
استفاده از کتابخانههای معتبر برای sanitize کردن HTML
پیادهسازی CSP
جدا کردن داده از کد
استفاده از فریمورکهایی که به صورت پیشفرض Escape انجام میدن
امنیت وب بیشتر از اینکه به «بستن چند تا تگ» مربوط باشه، به درک درست از نحوه تفسیر دادهها توسط مرورگر مربوطه.
۹۰ درصد xss های دنیا از دست بردن مرورگر توی کد و عدم ناهماهنگی بین مرورگر و وب اپلیکشن به وجود میاد.
دقیقاً همینجاست که تفاوت بین فیلتر سطحی و طراحی امن مشخص میشه
@dagen_security