حملات XSS
حملات XSS یا Cross-Site Scripting یکی از رایجترین آسیبپذیریهای امنیتی وب هستند که در آن مهاجم میتواند کد مخرب را در مرورگر کاربران اجرا کند. این آسیبپذیری ممکن است به سرقت اطلاعات، سوءاستفاده از نشست کاربران و دستکاری محتوای سایت منجر شود. در این مقاله با انواع XSS شامل Stored، Reflected و DOM-Based، نحوه شکلگیری این حملات و مهمترین روشهای شناسایی و جلوگیری از آنها آشنا میشوید.
حملات XSS یا Cross-Site Scripting یکی از شناختهشدهترین آسیبپذیریهای امنیتی در وب هستند؛ ضعفی که ممکن است در نگاه اول تنها به اجرای چند خط کد در مرورگر محدود به نظر برسد، اما در عمل میتواند امنیت حساب کاربران، اطلاعات حساس، نشستهای ورود، اعتبار یک وبسایت و حتی فرایندهای تجاری یک سامانه را تحت تأثیر قرار دهد.
در حمله XSS، مهاجم تلاش میکند محتوای کنترلنشده را وارد بخشی از وبسایت کند که مرورگر قربانی آن را بهعنوان کد قابل اجرا تفسیر میکند. نکته مهم این است که مشکل الزاماً از «جاوااسکریپت» شروع نمیشود؛ ریشه اصلی آسیبپذیری، مدیریت نادرست دادههای غیرقابل اعتماد هنگام نمایش آنها در صفحه وب است.
در تعریف CWE-79، این ضعف زمانی رخ میدهد که یک برنامه وب داده قابل کنترل توسط کاربر را بدون خنثیسازی مناسب در خروجی صفحه قرار دهد و مرورگر بتواند بخشی از آن داده را بهصورت محتوای اجرایی تفسیر کند.
به همین دلیل حملات XSS فقط مسئلهای مربوط به سایتهای قدیمی یا پروژههای کوچک نیستند. حتی برنامههایی که با فریمورکهای مدرن توسعه داده شدهاند نیز در صورت استفاده اشتباه از APIهای ناامن، دورزدن سیستم Escape خودکار، استفاده از HTML خام یا پردازش نادرست ورودیها ممکن است در برابر XSS آسیبپذیر شوند.
در این مقاله از رخنه کاو، حملات XSS را از پایه بررسی میکنیم، انواع XSS را توضیح میدهیم، تفاوت XSS ذخیرهشده، بازتابی و مبتنی بر DOM را بررسی میکنیم، خطرات آن را میشناسیم و مهمتر از همه، روشهای اصولی جلوگیری، شناسایی و مدیریت این آسیبپذیری را مرور خواهیم کرد.
حمله XSS چیست؟
XSS مخفف Cross-Site Scripting است و به دستهای از آسیبپذیریهای سمت کاربر گفته میشود که امکان قرار گرفتن داده کنترلشده توسط مهاجم در یک Context قابل اجرا در مرورگر را فراهم میکنند.
برای درک بهتر موضوع باید بدانیم که مرورگر هنگام دریافت یک صفحه وب فقط متن ساده نمایش نمیدهد. مرورگر HTML را تحلیل میکند، CSS را پردازش میکند، کد JavaScript را اجرا میکند، رویدادها را مدیریت میکند و منابع مختلف را از سرورهای دیگر دریافت میکند.
اگر برنامه نتواند میان «داده» و «کد» تمایز مناسبی ایجاد کند، ممکن است ورودیای که قرار بوده صرفاً به کاربر نمایش داده شود، به بخشی از ساختار اجرایی صفحه تبدیل شود.
فرض کنید یک سایت مقدار واردشده در یک فرم، پارامتر URL یا بخش نظرات را بدون پردازش صحیح در صفحه نمایش دهد. اگر این داده در جای نامناسبی از HTML قرار بگیرد، مرورگر ممکن است آن را بخشی از ساختار صفحه یا کد فعال در نظر بگیرد.
OWASP نیز XSS را در شرایطی توضیح میدهد که دادهای از یک منبع غیرقابل اعتماد وارد برنامه شده و سپس بدون محافظت کافی در محتوای پویا قرار گیرد.
نکته مهم این است که در بسیاری از حملات XSS، سرور هدف مستقیماً «هک» نمیشود. در عوض مهاجم کاری میکند که مرورگر کاربر، محتوای ناخواسته را در بستر دامنه معتبر اجرا یا پردازش کند.
همین ویژگی XSS را خطرناک میکند؛ زیرا کاربر تصور میکند همچنان با سایت اصلی و معتبر در ارتباط است.
چرا XSS یک آسیبپذیری مهم امنیتی محسوب میشود؟
ممکن است تصور شود اجرای کد در مرورگر یک کاربر خطر چندانی برای سرور ندارد، اما مرورگر کاربران به بخش مهمی از معماری برنامههای مدرن تبدیل شده است.
امروزه بسیاری از عملیات مهم مانند احراز هویت، مدیریت نشست، دسترسی به APIها، ذخیره اطلاعات محلی، ارسال درخواستهای حساس، نمایش پنل کاربری و اجرای منطق برنامه در مرورگر انجام میشوند.
اگر مهاجم بتواند کد خود را در Context یک سایت معتبر اجرا کند، بسته به معماری برنامه و سطح دسترسی قربانی، ممکن است بتواند به دادههایی دسترسی پیدا کند که یک اسکریپت عادی همان سایت نیز اجازه دسترسی به آنها را دارد.
سرقت یا سوءاستفاده از نشست کاربر
یکی از شناختهشدهترین خطرات XSS، سوءاستفاده از نشست کاربران است.
البته استفاده صحیح از Cookieهایی با ویژگی HttpOnly میتواند دسترسی مستقیم JavaScript به برخی Cookieهای حساس را محدود کند، اما این موضوع به معنی بیخطر شدن XSS نیست.
یک اسکریپت مخرب ممکن است بتواند در همان مرورگر قربانی درخواستهایی را با سطح دسترسی کاربر ارسال کند یا اطلاعاتی را از رابط کاربری استخراج کند.
بنابراین نباید جلوگیری از دسترسی مستقیم به Cookie را با جلوگیری کامل از XSS اشتباه گرفت.
دستکاری محتوای صفحه
کدی که در Context صفحه اجرا میشود ممکن است بتواند بخشهایی از DOM را تغییر دهد.
در سناریوهای واقعی این موضوع میتواند برای نمایش فرم جعلی، تغییر پیامهای سایت، دستکاری عناصر رابط کاربری یا نمایش لینکهای غیرواقعی مورد سوءاستفاده قرار گیرد.
کاربر همچنان دامنه اصلی را در نوار آدرس مشاهده میکند و همین موضوع میتواند تشخیص حمله را دشوارتر کند.
سرقت اطلاعات موجود در صفحه
اگر برنامه اطلاعات مهمی را در DOM یا JavaScript سمت کاربر نگه دارد، وجود XSS میتواند زمینه دسترسی مهاجم به این دادهها را فراهم کند.
اطلاعاتی مانند نام کاربر، ایمیل، دادههای صفحه حساب، تنظیمات، شناسههای داخلی یا دادههایی که از API دریافت شدهاند ممکن است در معرض خطر قرار بگیرند.
MDN نیز توضیح میدهد که کد اجراشده از طریق XSS میتواند، در محدوده دسترسی سایت، محتوای صفحه یا Storage مرورگر را بخواند یا تغییر دهد و درخواستهایی با اعتبار کاربر ایجاد کند.
انجام عملیات با سطح دسترسی قربانی
اگر قربانی یک مدیر سایت یا کاربری با دسترسی بالا باشد، شدت آسیب میتواند بیشتر شود.
برای مثال، اگر یک پنل مدیریتی در برابر XSS آسیبپذیر باشد، مهاجم ممکن است بتواند از Context نشست مدیر برای انجام برخی عملیات مجاز استفاده کند.
به همین دلیل وجود XSS در بخش مدیریت معمولاً باید با حساسیت بسیار بیشتری بررسی شود.
آسیب به اعتبار برند و اعتماد کاربران
آسیب XSS فقط فنی نیست.
نمایش محتوای جعلی، هدایت کاربران به صفحات نامعتبر، ایجاد فرمهای غیرواقعی یا اختلال در رابط سایت میتواند اعتماد کاربران به برند را کاهش دهد.
برای سایتهای فروشگاهی، مالی، شرکتی و سامانههایی که اطلاعات کاربران را مدیریت میکنند، چنین رویدادی ممکن است هزینه تجاری قابل توجهی ایجاد کند.
حملات XSS چگونه اتفاق میافتند؟
برای شکلگیری یک XSS معمولاً چند مرحله منطقی وجود دارد.
ابتدا دادهای از یک منبع غیرقابل اعتماد وارد برنامه میشود. این منبع ممکن است فرم، پارامتر URL، Header، API، Comment، نام کاربری، پیام، تنظیمات پروفایل یا حتی داده دریافتشده از سرویس دیگری باشد.
در مرحله بعد برنامه این داده را پردازش کرده و آن را در خروجی قرار میدهد.
مشکل زمانی ایجاد میشود که داده متناسب با Context مقصد Encode، Escape یا Sanitize نشده باشد.
مرورگر صفحه را دریافت میکند و اگر ساختار خروجی اجازه دهد، داده ورودی ممکن است به بخشی از HTML یا رفتار اجرایی صفحه تبدیل شود.
به زبان ساده، مشکل اصلی زمانی رخ میدهد که برنامه انتظار دارد مرورگر چیزی را «متن» در نظر بگیرد، اما مرورگر آن را «کد یا ساختار فعال» تفسیر میکند.
Source و Sink در XSS چه مفهومی دارند؟
یکی از مفاهیم مهم در تحلیل XSS، Source و Sink است.
Source چیست؟
Source نقطهای است که داده غیرقابل اعتماد از آن وارد برنامه میشود.
نمونههای رایج Source عبارتاند از:
- ورودی فرمها
- Query String
- Fragment URL
- اطلاعات دریافتشده از API
- دادههای ذخیرهشده کاربران
- Web Storage
- پیامهای بین پنجرهها
- برخی Headerهای HTTP
- اطلاعات پروفایل
- نظرات و پیامها
وجود یک Source بهتنهایی به معنی آسیبپذیری نیست.
خطر زمانی ایجاد میشود که داده Source بدون کنترل مناسب به یک Sink خطرناک برسد.
Sink چیست؟
Sink نقطهای است که داده وارد ساختاری میشود که ممکن است توسط مرورگر تفسیر یا اجرا شود.
برای مثال، برخی روشهای تغییر مستقیم HTML صفحه در صورت دریافت داده غیرقابل اعتماد میتوانند Sink پرریسک محسوب شوند.
OWASP توصیه میکند در صورت امکان از APIهایی استفاده شود که داده را بهصورت Text در DOM قرار میدهند، نه APIهایی که آن را بهعنوان HTML تفسیر میکنند.
در نتیجه، هنگام Code Review برای XSS باید مسیر حرکت داده را دنبال کرد:
Source → پردازش → Sink
اگر ورودی کنترلشده توسط کاربر بدون محافظت Context-Aware به Sink ناامن برسد، احتمال وجود XSS افزایش مییابد. 
انواع حملات XSS
XSS معمولاً به سه گروه اصلی تقسیم میشود:
- Reflected XSS
- Stored XSS
- DOM-Based XSS
هر سه نوع در نهایت به اجرای ناخواسته محتوا در مرورگر مربوط هستند، اما مسیر رسیدن داده مهاجم به صفحه قربانی در آنها متفاوت است.
Reflected XSS یا XSS بازتابی چیست؟
Reflected XSS زمانی اتفاق میافتد که ورودی کاربر از طریق یک درخواست وارد سرور شود و همان داده در پاسخ همان درخواست به صفحه بازگردانده شود.
به همین دلیل به آن XSS بازتابی یا غیرماندگار نیز گفته میشود.
Reflected XSS چگونه شکل میگیرد؟
فرض کنید یک صفحه جستجو عبارت جستجوشده را دوباره در عنوان صفحه نمایش دهد.
کاربر عبارتی را جستجو میکند و سایت مینویسد:
نتایج جستجو برای: عبارت کاربر
اگر توسعهدهنده مقدار جستجو را مستقیماً در HTML قرار دهد و Encoding صحیح انجام نشود، ممکن است Context خروجی قابل تغییر باشد.
در حملات واقعی، مهاجم معمولاً تلاش میکند قربانی را وادار به باز کردن یک URL یا ارسال درخواستی کند که داده کنترلشده در آن قرار دارد.
چرا Reflected XSS خطرناک است؟
Reflected XSS معمولاً نیازمند نوعی تعامل قربانی است؛ برای مثال باز کردن یک لینک.
اما این موضوع به معنی کماهمیت بودن آن نیست.
اگر سایت معتبر باشد، کاربر ممکن است به دامنه اعتماد کند و متوجه وجود داده مخرب در پارامترهای URL نشود.
صفحات جستجو، صفحات خطا، فرمهای ورود، صفحات Redirect و بخشهایی که داده URL را نمایش میدهند باید از این نظر بررسی شوند.
روش جلوگیری از Reflected XSS
مهمترین اصل این است که هر دادهای که وارد خروجی HTML میشود باید متناسب با Context مقصد پردازش شود.
اگر داده در متن HTML قرار دارد، باید HTML Encoding مناسب اعمال شود.
اگر در Attribute قرار دارد، باید Encoding مخصوص Attribute انجام شود.
اگر داده قرار است بخشی از URL باشد، باید URL Encoding مناسب اعمال شود و سپس Context نهایی نیز بررسی شود.
به همین دلیل استفاده از یک تابع Escape عمومی برای تمام شرایط، طراحی امنیتی مناسبی نیست. 
Stored XSS یا XSS ذخیرهشده چیست؟
Stored XSS یکی از مهمترین انواع حملات XSS است.
در این حالت داده کنترلشده توسط مهاجم ابتدا در سیستم ذخیره میشود و بعداً برای یک یا چند کاربر دیگر نمایش داده میشود.
این داده ممکن است در دیتابیس، فایل، Cache یا سیستم دیگری ذخیره شود.
Stored XSS در چه قسمتهایی دیده میشود؟
بخشهایی که محتوای کاربران را ذخیره و سپس نمایش میدهند بیشتر در معرض این نوع ضعف قرار دارند.
برای مثال:
- بخش نظرات
- انجمنها
- سیستمهای تیکت
- پیامهای خصوصی
- نام نمایشی کاربران
- توضیحات پروفایل
- محصولات Marketplace
- سیستمهای گفتگو
- داشبوردهای مدیریتی
- سیستم گزارش خطا
- محتوای واردشده از API خارجی
چرا Stored XSS اهمیت بیشتری دارد؟
در Reflected XSS معمولاً لازم است هر قربانی یک درخواست خاص ایجاد کند.
اما در Stored XSS، Payload در سامانه باقی میماند و هر کاربری که صفحه آسیبپذیر را مشاهده کند ممکن است در معرض آن قرار گیرد.
اگر محتوا در پنل مدیریت نمایش داده شود، حتی ممکن است هدف اصلی حمله مدیران یا اپراتورهای سایت باشند.
یک اشتباه رایج در مقابله با Stored XSS
برخی توسعهدهندگان تصور میکنند کافی است تمام Tagهای HTML را هنگام ذخیره اطلاعات حذف کنند.
این روش همیشه صحیح نیست.
نوع دفاع باید براساس Context استفاده از داده انتخاب شود.
برای دادهای که قرار است فقط متن ساده باشد، محدود کردن ورودی و Encoding خروجی انتخاب مناسبی است.
اما اگر کاربران مجاز به وارد کردن HTML محدود باشند، مانند ویرایشگر متن، باید از HTML Sanitization معتبر و Allowlist-Based استفاده کرد. 
DOM-Based XSS چیست؟
DOM-Based XSS با دو نوع قبلی تفاوت معماری مهمی دارد.
در این نوع، آسیبپذیری ممکن است کاملاً در JavaScript سمت مرورگر اتفاق بیفتد و سرور الزاماً نسخه مخرب داده را در HTML پاسخ خود قرار ندهد.
JavaScript صفحه دادهای را از یک Source دریافت میکند و سپس آن را به یک Sink ناامن منتقل میکند.
DOM در اینجا چه نقشی دارد؟
DOM یا Document Object Model ساختار قابل برنامهنویسی صفحه وب است.
JavaScript میتواند عناصر DOM را ایجاد، حذف یا تغییر دهد.
اگر داده غیرقابل اعتماد بهعنوان HTML یا کد وارد DOM شود، احتمال DOM XSS به وجود میآید.
نمونه مفهومی DOM XSS
فرض کنید یک برنامه مقدار خاصی را از URL دریافت میکند و برای نمایش پیام خوشآمدگویی از آن استفاده میکند.
اگر برنامه این مقدار را به شکل Text به صفحه اضافه کند، ریسک کاهش مییابد.
اما اگر همان مقدار مستقیماً بهعنوان HTML تفسیر شود، ممکن است شرایط لازم برای XSS ایجاد شود.
جلوگیری از DOM-Based XSS
بهترین رویکرد این است که داده غیرقابل اعتماد تا حد امکان وارد Sinkهای اجرایی نشود.
برای نمایش متن، APIهایی مانند textContent نسبت به قرار دادن مستقیم HTML انتخاب امنتری هستند.
اگر نمایش HTML واقعاً ضروری است، داده باید با یک Sanitizer معتبر و متناسب با نیاز برنامه پاکسازی شود.
تفاوت Stored XSS، Reflected XSS و DOM-Based XSS
| نوع XSS | محل اصلی پردازش | ماندگاری | نیاز به تعامل قربانی | نمونه محل وقوع |
|---|---|---|---|---|
| Reflected XSS | معمولاً سرور و پاسخ درخواست | موقت | معمولاً بله | جستجو، خطا، پارامتر URL |
| Stored XSS | داده ذخیرهشده در سامانه | ماندگار | گاهی فقط مشاهده صفحه کافی است | نظرات، پروفایل، تیکت |
| DOM-Based XSS | JavaScript سمت مرورگر | بسته به طراحی برنامه | متفاوت | SPAها و پردازش DOM |
این تقسیمبندی برای تحلیل مسیر داده مفید است، اما دفاع امنیتی نباید صرفاً براساس نام نوع XSS انجام شود.
در نهایت باید Source، Context خروجی و Sink نهایی مشخص شوند.
Context در XSS چیست و چرا اهمیت دارد؟
یکی از مهمترین اشتباهات در جلوگیری از XSS، استفاده از یک Escape یکسان برای تمام نقاط برنامه است.
داده میتواند در Contextهای مختلفی قرار بگیرد:
- متن HTML
- Attribute
- JavaScript
- URL
- CSS
- DOM
روش ایمنسازی داده در هر Context متفاوت است.
OWASP نیز تأکید میکند که Output Encoding باید براساس Context انجام شود و برخی Contextها اساساً آنقدر خطرناک هستند که بهتر است داده غیرقابل اعتماد در آنها قرار نگیرد.
HTML Encoding چیست؟
HTML Encoding فرایندی است که طی آن کاراکترهای دارای معنای ساختاری در HTML به نمایش متنی امن تبدیل میشوند.
هدف این نیست که داده کاربر حذف شود؛ بلکه هدف این است که مرورگر آن را «متن» تلقی کند.
برای مثال، علامتهایی که در HTML برای شروع یا پایان Tag استفاده میشوند باید در Context متنی به شکلی نمایش داده شوند که مرورگر آنها را بخشی از ساختار HTML در نظر نگیرد.
Encoding با Filtering چه تفاوتی دارد؟
Filtering تلاش میکند دادههای مشکوک را تشخیص داده و حذف کند.
Encoding رویکرد متفاوتی دارد: حتی اگر داده شامل کاراکترهای خاص باشد، آنها را به شکلی نمایش میدهد که معنی اجرایی خود را از دست بدهند.
در بسیاری از شرایط، Encoding صحیح و Context-Aware قابل اعتمادتر از جستجو برای «رشتههای خطرناک» است.
Input Validation چیست؟
Input Validation یعنی مشخص کنیم یک ورودی از نظر نوع، طول، ساختار و مجموعه مقادیر مجاز چه ویژگیهایی باید داشته باشد.
برای مثال اگر یک فیلد قرار است سن کاربر باشد، نیازی نیست هر نوع رشتهای را بپذیرد.
اگر فیلد کشور فقط باید یکی از گزینههای مشخص باشد، میتوان آن را با Allowlist اعتبارسنجی کرد.
آیا Input Validation بهتنهایی جلوی XSS را میگیرد؟
خیر.
اعتبارسنجی ورودی یک لایه مهم امنیتی است، اما جایگزین Output Encoding نیست.
ممکن است دادهای از نظر قوانین ورودی معتبر باشد، اما زمانی که در Context دیگری قرار میگیرد خطر ایجاد کند.
بهترین طراحی این است که:
ورودی اعتبارسنجی شود، داده متناسب با نیاز برنامه ذخیره شود و هنگام خروج نیز براساس Context مقصد Encode یا Sanitize شود.
Sanitization چیست؟
Sanitization معمولاً زمانی استفاده میشود که برنامه عمداً میخواهد بخشی از HTML را از کاربر دریافت کند.
برای مثال یک ویرایشگر متن ممکن است اجازه Bold، Link، List یا برخی Tagهای محدود را بدهد.
در چنین شرایطی نمیتوان تمام HTML را Encode کرد؛ زیرا دیگر قابلیت قالببندی وجود نخواهد داشت.
راهکار مناسب استفاده از Sanitizer قابل اعتماد است که فقط Tagها و Attributeهای مجاز را نگه دارد.
چرا ساخت Sanitizer اختصاصی خطرناک است؟
HTML و رفتار مرورگرها پیچیدهاند.
تنوع Tagها، Attributeها، Namespaceها، Encodingها و روشهای مختلف Parser باعث میشود ساخت یک Sanitizer اختصاصی قابل اعتماد بسیار دشوار باشد.
به همین دلیل بهتر است از کتابخانههای امنیتی شناختهشده و بهروز استفاده شود. 
Content Security Policy چیست؟
Content Security Policy یا CSP یک سیاست امنیتی مرورگر است که از طریق Header یا روشهای تعریفشده به مرورگر اعلام میکند چه منابع و کدهایی اجازه بارگذاری یا اجرا دارند.
CSP میتواند تأثیر برخی XSSها را کاهش دهد.
برای مثال، سیاست سختگیرانه میتواند اجرای اسکریپتهای Inline یا منابعی که مجوز لازم ندارند را محدود کند.
MDN، CSP را یکی از لایههای مهم کاهش خطر XSS معرفی میکند، اما همزمان تأکید میکند که CSP باید در کنار Encoding و Sanitization قرار گیرد، نه بهجای آنها.
Strict CSP چیست؟
یکی از رویکردهای توصیهشده استفاده از CSP سختگیرانه مبتنی بر Nonce یا Hash است.
در چنین معماریای مرورگر فقط اسکریپتهایی را اجرا میکند که سیاست سایت آنها را مجاز تشخیص دهد.
MDN توضیح میدهد که Strict CSP میتواند بسیاری از مسیرهای رایج اجرای XSS، مانند اسکریپت Inline غیرمجاز، برخی Event Handlerهای Inline و URLهای JavaScript را محدود کند.
آیا CSP بهتنهایی کافی است؟
خیر.
این یکی از اشتباهات رایج در طراحی امنیت وب است.
CSP یک لایه Defense in Depth است.
اگر برنامه در اصل داده کاربر را بهصورت ناامن در صفحه قرار دهد، آسیبپذیری اصلی همچنان وجود دارد.
OWASP نیز اتکای کامل به CSP برای رفع XSS را یک Anti-Pattern میداند.
HttpOnly چگونه به کاهش خطر XSS کمک میکند؟
HttpOnly یک Attribute برای Cookie است.
وقتی Cookie حساس با HttpOnly تنظیم شده باشد، JavaScript صفحه نمیتواند به روش معمول آن را بخواند.
این ویژگی میتواند سرقت مستقیم برخی Cookieهای نشست از طریق JavaScript را دشوارتر کند.
اما HttpOnly نباید بهعنوان راهکار جلوگیری از XSS در نظر گرفته شود.
حتی اگر Cookie قابل خواندن نباشد، اسکریپت مخرب ممکن است بتواند درخواستهایی را در Context نشست فعال کاربر ارسال کند.
بنابراین HttpOnly یک لایه کاهش اثر حمله است، نه درمان ریشه XSS.
SameSite Cookie چه ارتباطی با XSS دارد؟
ویژگی SameSite بیشتر برای کنترل ارسال Cookie در درخواستهای Cross-Site و کاهش برخی حملات CSRF طراحی شده است.
SameSite جایگزین دفاع در برابر XSS نیست.
حتی OWASP در راهنمای CSRF یادآوری میکند که وجود XSS میتواند بسیاری از کنترلهای ضد CSRF را بیاثر کند.
به همین دلیل امنیت سمت کاربر باید مجموعهای از کنترلها را شامل شود.
چرا فیلتر کردن کلمه script کافی نیست؟
یکی از قدیمیترین روشهای مقابله ضعیف با XSS جستجو و حذف چند رشته مشخص از ورودی است.
برای مثال برخی سیستمها فقط وجود نام یک Tag خاص را بررسی میکنند.
این روش از نظر امنیتی قابل اعتماد نیست.
مرورگر HTML را با قواعد پیچیدهای پردازش میکند و مسیرهای متعددی برای ایجاد رفتار فعال در صفحه وجود دارد.
OWASP نیز در راهنمای XSS Filter Evasion نشان میدهد که اتکا به Filterهای ساده برای جلوگیری از XSS ناقص است.
راهحل اصولی تشخیص «Payload بد» نیست؛ بلکه ایجاد معماریای است که داده غیرقابل اعتماد نتواند به کد تبدیل شود.
چرا Regex بهتنهایی راهکار مناسبی برای XSS نیست؟
Regular Expression برای اعتبارسنجی بسیاری از دادهها ابزار مفیدی است.
اما استفاده از Regex برای تشخیص تمام HTML یا تمام حالات XSS معمولاً اشتباه است.
HTML یک ساختار پیچیده دارد و رفتار Parser مرورگر را نمیتوان با چند Pattern ساده بهطور کامل مدل کرد.
Regex ممکن است بخشی از Input Validation باشد، اما نباید نقش Sanitizer کامل HTML را برعهده بگیرد.
Safe Sink چیست؟
Safe Sink نقطهای از برنامه است که داده ورودی را بهعنوان Text یا مقدار غیرقابل اجرا مدیریت میکند.
برای مثال اگر هدف نمایش نام یک کاربر در صفحه است، بهتر است از روشی استفاده شود که رشته را بهصورت Text وارد DOM کند.
OWASP نمونههایی مانند textContent را در دسته Sinkهای امنتر معرفی میکند.
Unsafe Sink چیست؟
Unsafe Sink روشی است که داده را در Contextی قرار میدهد که میتواند ساختار HTML یا رفتار اجرایی ایجاد کند.
وجود Unsafe Sink لزوماً به معنی آسیبپذیر بودن برنامه نیست؛ اما اگر ورودی کنترلشده توسط کاربر بدون Sanitization مناسب به آن برسد، ریسک افزایش مییابد.
نقش فریمورکهای مدرن در جلوگیری از XSS
React، Angular، Vue و سایر فریمورکهای مدرن بسیاری از دادهها را بهصورت پیشفرض Escape میکنند.
این ویژگی تعداد زیادی از XSSهای سنتی را کاهش داده است.
اما هیچ فریمورکی بهطور خودکار تمام اشتباهات امنیتی توسعهدهنده را اصلاح نمیکند.
XSS در React
React در حالت عادی مقادیر نمایشدادهشده را Escape میکند.
اما توسعهدهنده میتواند با قابلیتهایی که برای قرار دادن HTML خام طراحی شدهاند این محافظت را دور بزند.
OWASP نیز استفاده نادرست از dangerouslySetInnerHTML را یکی از نقاطی میداند که توسعهدهندگان React باید نسبت به آن هوشیار باشند.
اگر HTML خام از کاربر یا API غیرقابل اعتماد دریافت میشود، قبل از قرار گرفتن در صفحه باید Sanitization مناسب انجام شود.
XSS در Angular
Angular نیز بهطور پیشفرض بسیاری از مقادیر Template را مدیریت میکند.
بااینحال استفاده از APIهایی که مکانیزم Sanitization یا Trust مدل Angular را دور میزنند میتواند امنیت برنامه را کاهش دهد.
توسعهدهنده نباید صرفاً برای رفع یک خطا یا نمایش سریع HTML، داده غیرقابل اعتماد را Trusted اعلام کند.
XSS در Vue
Vue نیز در Interpolation معمول داده را Escape میکند.
اما هر قابلیتی که HTML خام را وارد DOM کند باید با حساسیت بیشتری استفاده شود.
قاعده کلی مستقل از فریمورک است:
اگر داده غیرقابل اعتماد قرار است به HTML تبدیل شود، باید مشخص باشد چرا این کار ضروری است و چه Sanitization قابل اعتمادی روی آن انجام شده است. 
XSS در سایتهای وردپرسی
وردپرس به دلیل تعداد بالای افزونهها، قالبها و کدهای شخصیسازیشده میتواند در صورت توسعه نادرست با آسیبپذیری XSS مواجه شود.
وجود یک XSS در وردپرس الزاماً به معنی آسیبپذیر بودن هسته وردپرس نیست.
در بسیاری از موارد مشکل میتواند به افزونه، قالب یا کد اختصاصی سایت مربوط باشد.
افزونههای قدیمی
افزونهای که مدت طولانی بهروزرسانی نشده ممکن است شامل آسیبپذیریهای شناختهشده باشد.
مدیر سایت باید افزونههای بلااستفاده را حذف کند و افزونههای فعال را مرتب بهروز نگه دارد.
قالبهای نامعتبر
استفاده از قالبهای Nulled یا دریافتشده از منابع ناشناس خطر امنیتی بالایی دارد.
علاوه بر XSS، چنین قالبهایی ممکن است حاوی Backdoor یا کدهای ناخواسته باشند.
خروجی ناامن در افزونه اختصاصی
یکی از مهمترین منابع XSS در توسعه وردپرس زمانی است که دادههای کاربران یا تنظیمات مستقیماً در HTML چاپ میشوند.
وردپرس مجموعهای از توابع Escape برای Contextهای مختلف در اختیار توسعهدهندگان قرار میدهد و باید براساس محل خروجی از روش مناسب استفاده شود.
ذخیره HTML بدون Sanitization
اگر افزونهای اجازه ورود HTML را میدهد، باید دقیقاً مشخص باشد چه Tagها و Attributeهایی مجاز هستند.
اعتماد مستقیم به محتوای ورودی میتواند Stored XSS ایجاد کند.
مهمترین نقاطی که باید برای XSS بررسی شوند
در یک ارزیابی امنیتی مجاز، تنها بررسی فرم ورود کافی نیست.
هر دادهای که کاربر یا سیستم خارجی بتواند کنترل کند باید بررسی شود.
فرم جستجو
مقدار جستجو معمولاً دوباره در صفحه نمایش داده میشود.
به همین دلیل صفحات Search یکی از نقاطی هستند که باید Output Encoding آنها بررسی شود.
صفحه خطا
برخی برنامهها URL، مسیر فایل یا پارامتر نامعتبر را داخل پیام خطا نمایش میدهند.
اگر این داده بدون Encoding چاپ شود، ممکن است آسیبپذیری ایجاد کند.
پروفایل کاربری
نام، Biography، Website، Location و سایر فیلدهای پروفایل ممکن است در صفحات مختلف نمایش داده شوند.
ذخیره شدن ورودی باعث میشود بررسی Stored XSS در این قسمت اهمیت داشته باشد.
نظرات و پیامها
هر سیستم User Generated Content نیازمند طراحی امنیتی دقیق است.
پنل مدیریت
پنل مدیریت نیز نباید از تست XSS حذف شود.
گاهی دادهای که یک کاربر عادی ایجاد کرده است، فقط در پنل مدیر نمایش داده میشود.
در چنین شرایطی Stored XSS میتواند مدیران را هدف قرار دهد.
APIها
حتی اگر API فقط JSON برگرداند، نحوه استفاده Client از داده اهمیت دارد.
JSON امن بهتنهایی تضمین نمیکند داده هنگام ورود به DOM نیز امن باشد.
روش شناسایی XSS در Code Review
Code Review یکی از مؤثرترین روشها برای پیدا کردن XSS است.
هدف اصلی پیدا کردن مسیرهایی است که داده غیرقابل اعتماد از Source به Sink میرسد.
ابتدا Sourceها را پیدا کنید
تمام ورودیهای برنامه مشخص شوند:
- Request Parameters
- Body
- Headers
- Database Content
- API Responses
- URL Fragment
- Local Storage
- User Content
سپس Sinkها را بررسی کنید
باید مشخص شود این دادهها در نهایت کجا استفاده میشوند.
آیا بهصورت Text نمایش داده میشوند؟
آیا داخل Attribute قرار میگیرند؟
آیا در URL استفاده میشوند؟
آیا وارد JavaScript میشوند؟
آیا به یک API تولید HTML داده میشوند؟
محافظت بین Source و Sink را بررسی کنید
وجود تابعی با نام Escape لزوماً کافی نیست.
باید مشخص شود آن تابع برای چه Contextی طراحی شده است.
اگر HTML Encoder روی دادهای که داخل JavaScript قرار میگیرد استفاده شود، ممکن است محافظت مورد انتظار ایجاد نشود.
اسکنرهای امنیتی چقدر در پیدا کردن XSS مؤثرند؟
ابزارهای DAST و Scannerهای امنیتی میتوانند بسیاری از XSSهای رایج را شناسایی کنند.
اما نتیجه اسکن نباید جای Code Review و تحلیل دستی را بگیرد.
OWASP نیز اشاره میکند ابزارهای اسکن میتوانند در پیدا کردن برخی نقاط کمک کنند، ولی پوشش آنها کامل نیست.
DOM XSSهای پیچیده، مسیرهای احراز هویتشده، Workflowهای چندمرحلهای و آسیبپذیریهای وابسته به Business Logic ممکن است به بررسی دستی نیاز داشته باشند.
تست XSS باید چگونه انجام شود؟
تست XSS باید فقط روی سامانهای انجام شود که مالک آن هستید یا مجوز صریح ارزیابی امنیتی آن را دارید.
در یک تست حرفهای هدف این نیست که حساب کاربران واقعی یا اطلاعات آنها در معرض خطر قرار گیرد.
استفاده از ورودیهای غیرمخرب
در مرحله اولیه میتوان از Markerهای ساده و غیرقابل اجرا استفاده کرد تا مشخص شود داده در کدام قسمت خروجی ظاهر میشود.
برای مثال یک رشته منحصربهفرد میتواند نشان دهد ورودی در HTML، Attribute، Script یا بخش دیگری قرار گرفته است.
Context را مشخص کنید
قبل از هر نتیجهگیری باید دید داده دقیقاً در کدام Context وارد صفحه میشود.
همین مرحله تعیین میکند چه نوع دفاعی مورد نیاز است.
رفتار مرورگر را بررسی کنید
مشاهده Source اولیه صفحه همیشه کافی نیست.
JavaScript ممکن است بعد از بارگذاری صفحه DOM را تغییر دهد.
برای بررسی DOM-Based XSS، DevTools مرورگر و تحلیل جریان داده اهمیت زیادی دارند.
آیا WAF جلوی XSS را میگیرد؟
Web Application Firewall میتواند بعضی Patternهای شناختهشده را مسدود کند و یک لایه امنیتی اضافه باشد.
اما WAF نباید راهکار اصلی جلوگیری از XSS باشد.
اگر کد برنامه داده را بهصورت ناامن پردازش کند، ریشه آسیبپذیری همچنان وجود دارد.
همچنین DOM-Based XSS ممکن است کاملاً در مرورگر اتفاق بیفتد و درخواست خاصی که WAF بتواند آن را تشخیص دهد وجود نداشته باشد.
OWASP نیز اتکای صرف به WAF را برای جلوگیری از XSS توصیه نمیکند.
اشتباهات رایج توسعهدهندگان در مقابله با XSS
Escape فقط در زمان ورود اطلاعات
یکی از اشتباهات رایج این است که داده فقط هنگام ذخیره شدن تغییر داده شود.
مشکل این رویکرد آن است که Context استفاده آینده داده مشخص نیست.
ممکن است همان داده یکبار در HTML، بار دیگر در Attribute و بار سوم داخل URL استفاده شود.
در بسیاری از معماریها بهتر است داده متناسب با نیاز برنامه ذخیره و هنگام خروج براساس Context Encode شود.
اعتماد به داده دیتابیس
دادهای که از دیتابیس میآید لزوماً امن نیست.
ممکن است آن داده ماهها قبل از طریق ورودی کاربر وارد شده باشد.
اصل امنیتی مناسب این است که Trust براساس منبع واقعی و Context تعیین شود، نه صرفاً محل فعلی ذخیره اطلاعات.
اعتماد به کاربران واردشده
Authenticated بودن به معنی Trusted بودن نیست.
کاربر عادی، فروشنده، نویسنده یا حتی حسابی که تصاحب شده است ممکن است داده مخرب ایجاد کند.
اعتماد به داده API
API خارجی یا Microservice دیگر نیز ممکن است داده غیرقابل اعتماد برگرداند.
Frontend باید هنگام قرار دادن این داده در DOM همان اصول امنیتی را رعایت کند.
حذف چند کاراکتر
حذف < یا > شاید برخی ورودیها را تغییر دهد، اما یک سیاست کامل امنیتی نیست.
محافظت باید Context-Aware باشد.
چکلیست جلوگیری از حملات XSS
برای کاهش خطر XSS میتوان این موارد را در چرخه توسعه و نگهداری سایت اجرا کرد:
- تمام ورودیهای غیرقابل اعتماد را شناسایی کنید.
- برای ورودیها Validation متناسب با Business Logic تعریف کنید.
- Output Encoding را متناسب با Context انجام دهید.
- از قرار دادن داده غیرقابل اعتماد در Contextهای خطرناک خودداری کنید.
- برای نمایش متن در DOM از Safe Sink استفاده کنید.
- در صورت نیاز واقعی به HTML، از Sanitizer معتبر استفاده کنید.
- قابلیتهای Unsafe HTML در فریمورکها را محدود کنید.
- CSP مناسب و ترجیحاً سختگیرانه پیادهسازی کنید.
- Cookieهای حساس را با تنظیمات امنیتی مناسب مانند HttpOnly و Secure مدیریت کنید.
- وابستگیها، افزونهها و فریمورکها را بهروز نگه دارید.
- کدهای Frontend و Backend را Code Review کنید.
- تستهای امنیتی را وارد CI/CD کنید.
- پس از تغییرات مهم دوباره تست امنیتی انجام دهید.
- گزارشهای CSP و خطاهای مرورگر را بررسی کنید.
- دسترسی کاربران و مدیران را براساس Least Privilege محدود کنید.
جلوگیری از XSS در چرخه توسعه نرمافزار
امنیت XSS نباید در آخرین مرحله پروژه و فقط هنگام تست نفوذ بررسی شود.
بهترین نتیجه زمانی به دست میآید که Secure Coding از مرحله طراحی وارد پروژه شود.
مرحله طراحی
در معماری مشخص کنید کدام بخشها HTML تولید میکنند و چه نوع User Generated Content وجود دارد.
مرحله توسعه
توسعهدهندگان باید از APIهای امن فریمورک استفاده کنند و Escape دستی را به حداقل برسانند.
Code Review
استفاده از Unsafe Sinkها باید در Review حساسیت بیشتری داشته باشد.
تست خودکار
SAST میتواند الگوهای مشکوک در کد را پیدا کند.
DAST نیز برخی رفتارهای آسیبپذیر را در برنامه در حال اجرا شناسایی میکند.
تست امنیتی دورهای
پس از تغییرات معماری، افزودن Plugin، تغییر Frontend یا توسعه Featureهای جدید، ارزیابی مجدد اهمیت دارد.
چگونه Stored XSS را در سیستمهای دارای ویرایشگر HTML کنترل کنیم؟
یکی از سختترین سناریوها زمانی است که برنامه عمداً باید HTML دریافت کند.
برای مثال:
- CMS
- Blog Editor
- سیستم ایمیل
- توضیحات محصول
- Knowledge Base
- Forum
در این حالت Encoding کامل HTML قابلیت مورد نیاز را از بین میبرد.
Allowlist تعریف کنید
بهجای تلاش برای شناسایی تمام Tagهای خطرناک، مجموعه کوچکی از Tagها و Attributeهای مجاز تعریف کنید.
Sanitizer معتبر استفاده کنید
Parser و Sanitizer باید HTML را به شکل واقعی تحلیل کنند، نه اینکه با Regex چند کلمه را حذف کنند.
URLها را نیز اعتبارسنجی کنید
حتی اگر Attribute لینک مجاز باشد، Scheme و مقصد URL نیز باید براساس سیاست برنامه بررسی شود.
بعد از Sanitization دوباره داده را تغییر ندهید
یکی از مشکلات رایج این است که داده ابتدا Sanitize شده ولی سپس با پردازش دیگری تغییر میکند و ساختار جدیدی ایجاد میشود.
XSS و Single Page Applicationها
در SPAها حجم زیادی از منطق برنامه در JavaScript اجرا میشود.
به همین دلیل DOM XSS اهمیت ویژهای دارد.
داده ممکن است بدون Reload صفحه از API دریافت شود، در Client پردازش شود و سپس وارد DOM شود.
در چنین معماریای ممکن است Backend هیچ HTML مخربی تولید نکرده باشد، اما Frontend داده را به روش ناامن نمایش دهد.
نکات مهم برای SPA
- از Bindingهای پیشفرض فریمورک استفاده کنید.
- HTML خام را فقط در شرایط ضروری استفاده کنید.
- APIهای DOM ناامن را شناسایی کنید.
- URL Fragment و Query Parameters را غیرقابل اعتماد در نظر بگیرید.
- داده API را Trusted فرض نکنید.
- CSP را بهعنوان لایه مکمل فعال کنید.
XSS و APIهای JSON
یک API ممکن است JSON کاملاً معتبر تولید کند و همچنان داده آن در مرحله بعد باعث XSS شود.
مثلاً API نام یک کاربر را بهصورت String برمیگرداند.
تا این مرحله مشکلی وجود ندارد.
اما اگر Frontend همان String را بهعنوان HTML وارد DOM کند، نقطه آسیبپذیری در Client ایجاد شده است.
به همین دلیل امنیت API و امنیت Rendering دو مسئله مرتبط اما جدا هستند.
XSS Blind چیست؟
Blind XSS معمولاً به نوعی Stored XSS گفته میشود که ورودی مهاجم در صفحهای اجرا میشود که خود او مستقیماً به آن دسترسی ندارد.
برای مثال دادهای توسط کاربر عادی ثبت میشود، اما فقط در داشبورد داخلی اپراتور نمایش داده میشود.
از دید توسعهدهنده این بخش ممکن است کمخطر به نظر برسد، زیرا عمومی نیست.
اما دقیقاً به همین دلیل میتواند هدف جذابی باشد.
تمام پنلهای داخلی، سیستمهای لاگ، CRM، تیکتینگ و ابزارهای پشتیبانی باید داده خارجی را غیرقابل اعتماد در نظر بگیرند.
تفاوت XSS با HTML Injection چیست؟
در HTML Injection مهاجم میتواند ساختار یا محتوای HTML صفحه را تغییر دهد، اما الزاماً امکان اجرای JavaScript وجود ندارد.
در XSS معمولاً امکان رسیدن به یک Context اجرایی یا رفتار فعال مطرح است.
بااینحال HTML Injection نیز بیخطر نیست.
نمایش فرم جعلی، تغییر لینکها یا دستکاری ظاهر صفحه میتواند در حملات فیشینگ و مهندسی اجتماعی استفاده شود.
تفاوت XSS با CSRF چیست؟
XSS و CSRF دو آسیبپذیری متفاوتاند.
در XSS، مهاجم تلاش میکند کد یا محتوای فعال را در Context سایت قربانی اجرا کند.
در CSRF، مهاجم تلاش میکند مرورگر کاربر واردشده را وادار کند درخواست ناخواستهای به سایت دیگری ارسال کند.
تفاوت مهم این است که XSS معمولاً قدرت بیشتری در Context همان سایت ایجاد میکند و حتی میتواند برخی دفاعهای CSRF را تحت تأثیر قرار دهد.
تفاوت XSS با SQL Injection چیست؟
SQL Injection در سمت پایگاه داده اتفاق میافتد و ریشه آن ترکیب ناامن داده با Query است.
XSS عمدتاً در لایه نمایش و مرورگر دیده میشود و ریشه آن ترکیب ناامن داده با Contextهای وب است.
اصل مشترک هر دو آسیبپذیری این است که برنامه نباید داده غیرقابل اعتماد را بهعنوان بخشی از دستور یا کد تفسیر کند.
در SQL Injection استفاده از Queryهای Parameterized اهمیت دارد.
در XSS نیز Context-Aware Output Encoding، Sanitization و Safe Sinkها نقش مشابهی در جدا کردن داده از کد دارند.
اگر سایت دچار XSS شده باشد چه کار کنیم؟
رفع یک XSS فقط با حذف یک ورودی مخرب تمام نمیشود.
ابتدا باید مشخص شود آسیبپذیری از کجا ایجاد شده است.
مسیر ورودی را شناسایی کنید
مشخص کنید داده از کدام Source وارد برنامه شده است.
Sink آسیبپذیر را پیدا کنید
ببینید داده در چه Contextی نمایش داده شده و چرا مرورگر آن را به شکل فعال تفسیر کرده است.
ریشه مشکل را اصلاح کنید
اگر مشکل Output Encoding است، Context مناسب را اصلاح کنید.
اگر HTML خام لازم است، Sanitizer معتبر اضافه کنید.
اگر Unsafe Sink وجود دارد، آن را در صورت امکان با Safe Sink جایگزین کنید.
دادههای ذخیرهشده را بررسی کنید
در Stored XSS، اصلاح کد جدید کافی نیست.
ممکن است داده مخرب همچنان در دیتابیس باقی مانده باشد.
Logها را تحلیل کنید
مشخص کنید آسیبپذیری از چه زمانی قابل بهرهبرداری بوده و آیا نشانهای از سوءاستفاده وجود دارد.
نشستهای حساس را بررسی کنید
اگر شواهدی از Exploit وجود دارد، بسته به معماری سامانه ممکن است لازم باشد نشستهای کاربران حساس باطل شوند.
CSP را تقویت کنید
پس از رفع Root Cause میتوان CSP را نیز برای کاهش اثر خطاهای مشابه آینده تقویت کرد.
اولویتبندی شدت آسیبپذیری XSS
تمام XSSها شدت یکسانی ندارند.
برای ارزیابی ریسک باید Context واقعی برنامه بررسی شود.
سطح دسترسی قربانی
XSSی که فقط کاربران مهمان را تحت تأثیر قرار میدهد با XSSی که پنل مدیر را هدف میگیرد یکسان نیست.
Stored یا Reflected بودن
Stored XSS معمولاً دامنه اثر بیشتری دارد، اما یک Reflected XSS در صفحه حساس نیز میتواند بسیار مهم باشد.
وجود CSP
CSP سختگیرانه ممکن است برخی مسیرهای Exploit را محدود کند.
نوع اطلاعات صفحه
صفحهای که اطلاعات مالی یا شخصی نمایش میدهد حساستر است.
قابلیت انجام عملیات
اگر اسکریپت بتواند در Context نشست قربانی عملیات حساس انجام دهد، شدت افزایش مییابد.
آیا HTTPS جلوی XSS را میگیرد؟
خیر.
HTTPS ارتباط میان مرورگر و سرور را رمزنگاری میکند و از شنود یا تغییر ساده ترافیک در مسیر جلوگیری میکند.
اما اگر خود برنامه محتوای غیرقابل اعتماد را به شکل ناامن در صفحه قرار دهد، HTTPS نمیتواند آن مشکل منطقی را اصلاح کند.
داشتن قفل HTTPS به معنی امن بودن برنامه در برابر XSS، SQL Injection یا سایر آسیبپذیریهای نرمافزاری نیست.
آیا آنتیویروس جلوی XSS را میگیرد؟
معمولاً نباید به آنتیویروس کاربر برای جلوگیری از XSS وابسته بود.
XSS در بستر یک سایت معتبر و داخل مرورگر اجرا میشود.
راهکار اصلی باید در خود برنامه، مرورگر و Policyهای امنیتی آن پیادهسازی شود.
آیا مرورگرها XSS را خودکار مسدود میکنند؟
مرورگرهای مدرن کنترلهای امنیتی زیادی دارند، اما توسعهدهنده نباید فرض کند مرورگر تمام XSSها را شناسایی خواهد کرد.
برخی قابلیتهای قدیمی XSS Filter نیز در مرورگرهای مدرن کنار گذاشته شدهاند.
معماری ایمن باید بدون وابستگی به تشخیص خودکار Payload توسط مرورگر طراحی شود.
اهمیت بهروزرسانی کتابخانههای Sanitization
حتی اگر از Sanitizer معتبر استفاده شود، باید نسخه آن بهروز باشد.
Parserهای HTML، Browser Behavior و روشهای دور زدن Sanitization در طول زمان تغییر میکنند.
Dependency Management بخشی از امنیت XSS است.
برای پروژههای بزرگ بهتر است سامانهای برای شناسایی نسخههای آسیبپذیر کتابخانهها در CI/CD وجود داشته باشد.
نقش Trusted Types در امنیت XSS
Trusted Types یکی از قابلیتهای امنیتی مرورگرهای پشتیبانیشده است که میتواند به کاهش دستهای از DOM XSSها کمک کند.
ایده اصلی این است که APIهای حساس DOM نتوانند هر String دلخواهی را بهعنوان HTML یا Script دریافت کنند و برنامه مجبور شود داده را از Policyهای مشخص عبور دهد.
Trusted Types میتواند برای پروژههای بزرگ Client-Side یک لایه دفاعی قدرتمند باشد، بهخصوص زمانی که همراه با CSP و Sanitization مناسب استفاده شود.
اما مانند CSP، این قابلیت نیز جایگزین Secure Coding نیست.
سیاست امنیتی مناسب برای پروژههای جدید
اگر پروژهای از ابتدا طراحی میشود، جلوگیری از XSS بسیار سادهتر از اصلاح یک سیستم Legacy خواهد بود.
چند تصمیم معماری میتوانند سطح حمله را بهشدت کاهش دهند:
- استفاده از Template Engine با Auto-Escaping
- ممنوع کردن HTML خام مگر در موارد ضروری
- تعریف Component مشخص برای Sanitized HTML
- استفاده از Safe DOM APIs
- تعریف Strict CSP
- ممنوع کردن Inline JavaScript تا حد امکان
- جداسازی داده و Presentation
- اعتبارسنجی Schema ورودی API
- Security Review برای Featureهای User Generated Content
سیاست امنیتی برای پروژههای قدیمی
در پروژه Legacy معمولاً نمیتوان تمام کد را یکباره بازنویسی کرد.
در این شرایط باید رویکرد مرحلهای داشت.
نقاط حساس را اولویتبندی کنید
پنل مدیریت، صفحات احراز هویت، پرداخت، حساب کاربری و بخشهای دارای User Generated Content در اولویت هستند.
Unsafe Sinkها را فهرست کنید
یک Code Search میتواند نقاط استفاده از APIهای تولید HTML را پیدا کند.
CSP را ابتدا در حالت Report اجرا کنید
در پروژههایی که JavaScript Inline زیادی دارند، فعال کردن ناگهانی CSP سختگیرانه ممکن است سایت را مختل کند.
میتوان ابتدا گزارشها را جمعآوری و سپس Policy را مرحلهبهمرحله سختتر کرد.
Refactor تدریجی انجام دهید
هر Feature جدید باید مطابق استاندارد امن نوشته شود و هنگام تغییر کدهای قدیمی نیز Debt امنیتی کاهش یابد.
آموزش تیم توسعه چه نقشی در جلوگیری از XSS دارد؟
بسیاری از آسیبپذیریهای XSS نتیجه نبود کتابخانه امنیتی نیستند؛ بلکه از تصمیمهای اشتباه هنگام توسعه ناشی میشوند.
توسعهدهنده باید تفاوت بین HTML Encoding، URL Encoding و Sanitization را بداند.
Frontend Developer باید Source و Sinkهای DOM را بشناسد.
Backend Developer باید Context نهایی داده را درک کند.
Code Reviewer نیز باید بتواند مسیر داده را از ورودی تا خروجی دنبال کند.
یک استاندارد Secure Coding داخلی میتواند تعداد این خطاها را به شکل محسوسی کاهش دهد.
آیا حذف JavaScript از سایت XSS را حل میکند؟
در سایتهای مدرن این راهکار عملاً قابل اجرا نیست و حتی از نظر مفهومی نیز مسئله را کامل حل نمیکند.
XSS به مدیریت نادرست داده در Context صفحه مربوط است.
بهجای حذف فناوری، باید مرز میان داده غیرقابل اعتماد و کد اجرایی درست طراحی شود. 
بهترین رویکرد دفاعی در برابر XSS چیست؟
هیچ کنترل واحدی پاسخ تمام شرایط نیست.
مدل مناسب یک دفاع چندلایه است.
لایه اول، کاهش سطح حمله از طریق طراحی امن است.
لایه دوم، Input Validation است.
لایه سوم، Context-Aware Output Encoding است.
در بخشهایی که HTML مجاز است، Sanitization معتبر اضافه میشود.
در سمت Browser نیز CSP و در پروژههای مناسب Trusted Types میتوانند لایههای مکمل باشند.
Cookieهای امنیتی، Least Privilege، Code Review، تست امنیتی و Dependency Management نیز تأثیر یک آسیبپذیری احتمالی را کاهش میدهند.
همین فلسفه دفاع چندلایه است که باعث میشود شکست یک کنترل لزوماً به تصاحب کامل حساب یا آسیب گسترده منجر نشود.
سوالات متداول درباره حملات XSS
XSS مخفف چیست؟
XSS مخفف Cross-Site Scripting است.
از آنجا که CSS قبلاً برای Cascading Style Sheets استفاده میشد، اصطلاح XSS برای جلوگیری از ابهام رایج شد.
آیا XSS فقط با JavaScript انجام میشود؟
خیر.
گرچه JavaScript رایجترین زبان مرتبط با XSS است، ریشه آسیبپذیری به قرار گرفتن داده غیرقابل اعتماد در Context قابل تفسیر مرورگر مربوط میشود.
خطرناکترین نوع XSS کدام است؟
نمیتوان همیشه یک نوع را خطرناکترین دانست.
Stored XSS معمولاً به دلیل ماندگاری و امکان تأثیر بر چندین کاربر ریسک بالایی دارد، اما یک Reflected یا DOM XSS در صفحه بسیار حساس نیز میتواند شدت بالایی داشته باشد.
آیا وردپرس در برابر XSS آسیبپذیر است؟
هر برنامه وب ممکن است در صورت وجود کد ناامن دچار XSS شود.
در وردپرس، هسته، افزونهها، قالبها و کدهای اختصاصی باید جداگانه بررسی شوند.
بهروز نگه داشتن هسته و افزونهها، حذف افزونههای غیرضروری و استفاده از منابع معتبر اهمیت زیادی دارد.
آیا افزونه امنیتی وردپرس XSS را بهطور کامل متوقف میکند؟
خیر.
افزونه امنیتی یا WAF میتواند برخی حملات را کاهش دهد، اما اگر کد افزونه یا قالب داده را بهصورت ناامن نمایش دهد، Root Cause همچنان وجود دارد.
آیا CSP تمام حملات XSS را متوقف میکند؟
خیر.
CSP یک لایه مکمل بسیار مهم است، اما نباید جایگزین Output Encoding، Sanitization و Secure Coding شود.
آیا HttpOnly از XSS جلوگیری میکند؟
HttpOnly جلوی ایجاد XSS را نمیگیرد.
این ویژگی تنها دسترسی مستقیم JavaScript به Cookie دارای HttpOnly را محدود میکند و میتواند بخشی از اثر حمله را کاهش دهد.
آیا Encoding و Sanitization یکسان هستند؟
خیر.
Encoding داده را برای Context مشخص به شکل Text امن نمایش میدهد.
Sanitization معمولاً برای حالتی استفاده میشود که بخشی از HTML باید مجاز باقی بماند و محتوای خطرناک حذف شود.
برای پیدا کردن XSS اسکنر کافی است؟
خیر.
Scanner میتواند بخشی از آسیبپذیریها را پیدا کند، اما Code Review، تحلیل Source و Sink و بررسی دستی برنامههای پیچیده همچنان اهمیت دارد.
آیا XSS فقط سایتهای بزرگ را تهدید میکند؟
خیر.
وبلاگ شخصی، فروشگاه اینترنتی، سایت شرکتی، سامانه SaaS، پنل سازمانی و حتی برنامههای کوچک میتوانند در معرض XSS قرار بگیرند.
میزان ریسک به نوع اطلاعات، کاربران و قابلیتهای برنامه بستگی دارد.
جمعبندی
حملات XSS از قدیمیترین آسیبپذیریهای وب هستند، اما همچنان در برنامههای مدرن دیده میشوند. دلیل ماندگاری این ضعف نیز روشن است: برنامههای وب دائماً دادههای مختلفی را از کاربران، APIها، دیتابیس و مرورگر دریافت میکنند و همان دادهها را در Contextهای متفاوت نمایش میدهند.
هرجا مرز میان «داده» و «کد» بهدرستی رعایت نشود، احتمال ایجاد Cross-Site Scripting وجود دارد.
سه نوع شناختهشده XSS یعنی Reflected XSS، Stored XSS و DOM-Based XSS مسیرهای متفاوتی دارند، اما دفاع اصولی در برابر آنها بر مجموعهای از قواعد مشترک استوار است.
ورودی باید اعتبارسنجی شود، خروجی باید براساس Context Encode شود، HTML مجاز باید با Sanitizer معتبر پاکسازی شود و داده غیرقابل اعتماد نباید وارد Sinkهای خطرناک شود.
در کنار این موارد، Content Security Policy، Cookieهای امن، Trusted Types، بهروزرسانی وابستگیها، Code Review و تست امنیتی میتوانند دفاع چندلایهای ایجاد کنند.
مهمترین نکته این است که XSS را نباید با چند Filter ساده، Regex، WAF یا حذف چند Tag حلشده تصور کرد. راهکار واقعی، طراحی برنامهای است که در آن داده غیرقابل اعتماد از ابتدا تا لحظه نمایش تحت کنترل باشد.
برای مدیران سایت نیز بهروزرسانی سیستم مدیریت محتوا، افزونهها و قالبها، حذف اجزای بلااستفاده و انجام ارزیابی امنیتی دورهای اهمیت زیادی دارد. در پروژههای اختصاصی نیز Secure Coding باید از مرحله طراحی وارد چرخه توسعه شود، نه اینکه پس از انتشار محصول و مشاهده اولین آسیبپذیری به آن فکر شود.
هرچه زودتر XSS در چرخه توسعه شناسایی شود، هزینه اصلاح کمتر و احتمال آسیب به کاربران نیز پایینتر خواهد بود. به همین دلیل بررسی Cross-Site Scripting باید یکی از بخشهای ثابت Code Review، تست امنیت وب و فرایند نگهداری هر سامانه آنلاین باشد.