Clickjacking (کلیک‌ربایی) یا UI Redressing (بازآرایی رابط کاربری) یکی از پنهان‌کارترین حملات سمت مرورگر است که در آن مهاجم با لایه‌گذاری شفاف یک صفحه روی رابط هدف، کاربر را وادار می‌کند روی دکمه‌ای نامرئی کلیک کند. وردپرس به دلیل پیشخوان پرمحتوا و دکمه‌های حساس مانند حذف افزونه، تغییر نقش کاربر و تأیید پرداخت، هدف جذابی برای این حمله است. دفاع اصلی، ارسال هدرهای X-Frame-Options و Content-Security-Policy با دایرکتیو frame-ancestors است. پیاده‌سازی این هدرها در وردپرس از طریق فیلتر wp_headers، فایل htaccess. یا تنظیمات وب‌سرور انجام می‌شود. بدون این لایه، حتی سایت‌های به‌ظاهر امن نیز می‌توانند قربانی کلیک‌ربایی شوند و مهاجم بدون اطلاع کاربر، عملیات حساسی را اجرا کند.

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

Clickjacking چیست و چرا یک تهدید جدی محسوب می‌شود؟

Clickjacking (کلیک‌ربایی) که با نام‌های دیگری مانند UI Redressing (بازآرایی رابط کاربری)، Likejacking و Cursorjacking نیز شناخته می‌شود، نوعی حمله سمت کلاینت است که در آن مهاجم با استفاده از iframe، صفحه‌ای شفاف یا کم‌رنگ را روی یک رابط کاربری هدف قرار می‌دهد. کاربر گمان می‌کند روی دکمه‌ای بی‌خطر مانند «پخش ویدئو» یا «برنده جایزه شوید» کلیک می‌کند، اما در واقع روی دکمه‌ای حساس مانند «حذف حساب»، «تأیید پرداخت» یا «افزودن مدیر جدید» در پنل قربانی کلیک کرده است.

تفاوت بنیادین Clickjacking با XSS (Cross-Site Scripting - اسکریپت‌نویسی میان‌سایتی) این است که در XSS مهاجم کد دلخواه در سایت قربانی اجرا می‌کند، اما در Clickjacking هیچ کدی در سایت قربانی اجرا نمی‌شود؛ بلکه از اعتماد مرورگر به iframe سوءاستفاده می‌شود. به همین دلیل، ابزارهای سنتی امنیتی که روی تزریق ورودی تمرکز دارند، این حمله را نمی‌بینند. اگر می‌خواهید تفاوت این دو را عمیق‌تر بررسی کنید، پیشنهاد می‌کنم راهنمای پیشگیری از حملات XSS را مطالعه کنید.

بر اساس داده‌های منتشرشده در گزارش‌های OWASP (Open Web Application Security Project - پروژه امنیت برنامه‌های وب)، Clickjacking در دسته «حملات سمت مرورگر» طبقه‌بندی می‌شود و در بسیاری از ارزیابی‌های نفوذ، به‌عنوان یک نقص با شدت متوسط تا بالا گزارش می‌شود. آمار CVE (Common Vulnerabilities and Exposures - آسیب‌پذیری‌های رایج و مواجهه‌ها) نشان می‌دهد تعداد موارد مرتبط با Clickjacking در افزونه‌های وردپرسی در چند سال گذشته رشد قابل توجهی داشته است.

آنچه Clickjacking را خطرناک‌تر می‌کند، ترکیب آن با حملات دیگر است. مهاجم می‌تواند با CSRF (Cross-Site Request Forgery - جعل درخواست میان‌سایتی) یا XSS ترکیب کند و سطح تخریب را چند برابر کند. برای درک عمیق‌تر این هم‌پوشانی، حملات CSRF و روش‌های دفع را ببینید.

چرا وردپرس هدف جذابی برای Clickjacking است؟

وردپرس به دلیل سهم بازار بالای خود — که طبق آمار W3Techs در محدوده ۴۰ درصد از کل وب‌سایت‌ها قرار دارد — به‌طور طبیعی هدف اصلی مهاجمان است. اما فراتر از سهم بازار، دلایل فنی مشخصی وجود دارد که وردپرس را برای Clickjacking جذاب می‌کند:

  • پیشخوان مدیریتی پرمحتوا: اکثر اقدامات حساس در پیشخوان انجام می‌شود؛ از حذف کاربر تا تغییر نقش و نصب افزونه.
  • دکمه‌های بدون تأیید مضاعف: بسیاری از اقدامات با یک کلیک ساده اجرا می‌شوند و هیچ تأیید ثانویه‌ای ندارند.
  • فرم‌های AJAX محور: رابط کاربری وردپرس مدرن به‌شدت روی AJAX بنا شده و همین موضوع، تشخیص کلیک جعلی را سخت‌تر می‌کند.
  • افزونه‌های شخص‌ثالث: بسیاری از افزونه‌ها هدرهای امنیتی لازم را ارسال نمی‌کنند و وردپرس نیز به‌صورت پیش‌فرض این هدرها را برای همه صفحات فعال نمی‌کند.

نکته مهم این است که وردپرس به‌طور پیش‌فرض هدر X-Frame-Options را برای صفحات مدیریتی ارسال نمی‌کند (مگر در نسخه‌های جدیدتر که برخی موارد تقویت شده‌اند). این بدان معناست که اگر سایت شما روی یک سرور بدون تنظیمات امنیتی اضافی اجرا شود، اگر مهاجم بتواند کاربر مدیر را به صفحه‌ای مخرب بکشاند، احتمال موفقیت حمله بالا است. این دقیقاً همان چیزی است که آن را به یک آسیب‌پذیری وب جدی تبدیل می‌کند.

مکانیزم فنی حمله Clickjacking

برای دفاع مؤثر، ابتدا باید مکانیزم دقیق حمله را بشناسیم. Clickjacking در سطحی‌ترین لایه، بر سه ستون استوار است: لایه‌گذاری، شفافیت و فریب ادراکی.

لایه‌گذاری و Iframe

مهاجم یک صفحه HTML می‌سازد که در آن یک <iframe> با src به سایت قربانی (مثلاً https://victim.com/wp-admin/user-new.php) قرار می‌دهد. سپس با استفاده از CSS (Cascading Style Sheets - شیوه‌نامه آبشاری)، این iframe را با opacity: 0 یا position: absolute شفاف کرده و روی یک دکمه فریبنده قرار می‌دهد.

<div style="position:relative; width:300px; height:100px;">
  <iframe src="https://victim.com/wp-admin/user-new.php"
          style="position:absolute; top:0; left:0;
                 width:300px; height:100px;
                 opacity:0; z-index:2;">
  </iframe>
  <button style="position:absolute; top:40px; left:60px;
                 z-index:1;">برنده شوید!</button>
</div>

کاربر روی دکمه «برنده شوید» کلیک می‌کند، اما در واقع کلیک روی دکمه «افزودن کاربر» در پیشخوان وردپرس فرود می‌آید. اگر کاربر لاگین باشد، وردپرس درخواست را معتبر می‌داند و کاربر جدید با نقش دلخواه مهاجم ساخته می‌شود.

Likejacking و Cursorjacking

Likejacking نسخه‌ای از این حمله است که روی دکمه‌های «لایک» شبکه‌های اجتماعی تمرکز می‌کند. Cursorjacking اما پیشرفته‌تر است: در این روش، نشانگر ماوس کاربر با یک نشانگر جعلی جایگزین می‌شود و حتی اگر کاربر ماوس را حرکت دهد، نشانگر واقعی جای دیگری است. این تکنیک در سال‌های اخیر با استفاده از فناوری‌های مرورگری کمتر شناخته‌شده مانند Pointer Events و CSS Shapes توسعه یافته است.

Clickjacking در برابر CSRF

بسیاری Clickjacking را با CSRF اشتباه می‌گیرند. تفاوت کلیدی در این است که در CSRF، مهاجم از اعتماد سایت به مرورگر قربانی سوءاستفاده می‌کند و درخواست را بدون اطلاع کاربر ارسال می‌کند؛ اما در Clickjacking، کاربر واقعاً کلیک می‌کند و توکن‌های ضد-CSRF (مانند wp_nonce) نیز معتبر تلقی می‌شوند. به همین دلیل، توکن‌های CSRF در برابر Clickjacking محافظت ایجاد نمی‌کنند. اگر می‌خواهید تفاوت این دو را عمیق‌تر ببینید، انواع آسیب‌پذیری‌های رایج وب را بررسی کنید.

توکن CSRF فقط ثابت می‌کند درخواست از فرم سایت آمده؛ اما در Clickjacking، فرم سایت واقعاً کلیک شده است. دفاع در لایه دیگری لازم است.

دفاع اول: هدر X-Frame-Options

هدر X-Frame-Options یک هدر پاسخ HTTP (Hypertext Transfer Protocol - پروتکل انتقال ابرمتن) است که به مرورگر می‌گوید آیا اجازه دارد صفحه فعلی را درون <iframe>، <frame> یا <object> نمایش دهد یا نه. این هدر سه مقدار اصلی می‌پذیرد:

مقدارتوضیحسناریوی پیشنهادی
DENYهیچ سایتی اجازه قاب‌بندی نداردپیشخوان وردپرس، صفحات پرداخت
SAMEORIGINفقط دامنه‌های هم‌ریشه مجازندسایت‌هایی که در چند زیردامنه قاب‌بندی می‌شوند
ALLOW-FROM uriفقط دامنه مشخص مجاز است (پشتیبانی محدود)یکپارچه‌سازی با پنل‌های مشخص

نکته مهم: مقدار ALLOW-FROM به‌طور کامل توسط همه مرورگرها پشتیبانی نمی‌شود و در عمل، استفاده از CSP (Content Security Policy - سیاست امنیتی محتوا) توصیه می‌شود. برای درک جامع هدرهای امنیتی، راهنمای هدرهای امنیتی HTTP را مطالعه کنید.

دفاع دوم: CSP frame-ancestors

CSP یا Content Security Policy یک لایه دفاعی قوی‌تر است که در سطح دایرکتیو، امکان کنترل دقیق‌تری فراهم می‌کند. دایرکتیو frame-ancestors مشخص می‌کند چه دامنه‌هایی می‌توانند صفحه فعلی را قاب‌بندی کنند. مثال:

Content-Security-Policy: frame-ancestors 'self';

یا برای مسدودسازی کامل:

Content-Security-Policy: frame-ancestors 'none';

مزیت CSP frame-ancestors نسبت به X-Frame-Options چند مورد است: اول آنکه امکان تعریف چند دامنه (با فاصله) را می‌دهد، دوم آنکه در صورت وجود دایرکتیو report-uri، می‌توان نقض‌ها را مانیتور کرد، و سوم آنکه مرورگرهای مدرن آن را ترجیح می‌دهند. نقطه ضعف آن، عدم پشتیبانی در نسخه‌های قدیمی Internet Explorer است که امروزه تقریباً بی‌اهمیت است.

X-Frame-Options و CSP frame-ancestors را هم‌زمان ارسال کنید. مرورگرهای مدرن CSP را ترجیح می‌دهند و مرورگرهای قدیمی به X-Frame-Options برمی‌گردند.

مقایسه X-Frame-Options و CSP frame-ancestors

ویژگیX-Frame-OptionsCSP frame-ancestors
پشتیبانی مرورگرتمام مرورگرهاهمه مرورگرهای مدرن
چند دامنهخیر (به جز ALLOW-FROM)بله
گزارش نقضخیربله (report-uri)
اولویت مرورگر مدرنپایینبالا
پیچیدگی پیاده‌سازیسادهمتوسط

جمع‌بندی این مقایسه ساده است: اگر فقط یک لایه می‌خواهید، CSP frame-ancestors را انتخاب کنید. اگر می‌خواهید سازگاری حداکثری داشته باشید، هر دو را کنار هم ارسال کنید.

پیاده‌سازی Clickjacking Prevention در وردپرس

در وردپرس، سه مسیر اصلی برای پیاده‌سازی این هدرها وجود دارد که هرکدام مزایا و محدودیت‌های خود را دارند.

روش اول: فیلتر wp_headers در functions.php

این روش انعطاف‌پذیرترین گزینه است. با استفاده از فیلتر wp_headers، می‌توانید هدرها را قبل از ارسال به مرورگر تنظیم کنید:

add_filter( 'wp_headers', function( $headers ) {
    $headers['X-Frame-Options'] = 'SAMEORIGIN';
    $headers['Content-Security-Policy'] = "frame-ancestors 'self'";
    return $headers;
} );

اگر می‌خواهید این هدرها فقط برای پیشخوان اعمال شوند:

add_action( 'admin_init', function() {
    header( 'X-Frame-Options: DENY' );
    header( "Content-Security-Policy: frame-ancestors 'none'" );
} );

توجه داشته باشید که این کد باید در یک چایلد تم یا افزونه اختصاصی قرار گیرد، نه در فایل functions.php قالب اصلی.

روش دوم: htaccess.

<IfModule mod_headers.c>
  Header always set X-Frame-Options "SAMEORIGIN"
  Header always set Content-Security-Policy "frame-ancestors 'self'"
</IfModule>

مزیت این روش، اعمال در سطح وب‌سرور و عدم وابستگی به PHP است. عیب آن این است که روی سرورهای Nginx کار نمی‌کند و برای Nginx باید در بلوک server تنظیم شود.

روش سوم: افزونه‌های امنیتی

افزونه‌هایی مانند Wordfence، Sucuri و iThemes Security گزینه‌هایی برای فعال‌سازی این هدرها در رابط کاربری دارند. اگر می‌خواهید گزینه‌های حرفه‌ای‌تر را ببینید، بهترین افزونه‌های امنیتی وردپرس را ببینید.

Frame Busting JavaScript و محدودیت‌های آن

روش قدیمی‌تر، استفاده از JavaScript برای «شکستن قاب» بود:

if (top !== self) { top.location = self.location; }

این روش امروزه ناکافی است، زیرا:

  • اگر کاربر JavaScript را غیرفعال کند، حمله کار می‌کند.
  • مهاجم می‌تواند با sandbox attribute در iframe، اجرای JavaScript را مسدود کند.
  • در برخی مرورگرها، دسترسی به top.location در iframe محدود شده و خطا می‌دهد.

به همین دلیل، Frame Busting تنها باید به‌عنوان لایه دفاعی سوم و نه اول در نظر گرفته شود. این رویکرد «دفاع در عمق» (Defense in Depth) در اصول امنیت وب توضیح داده شده است.

تست Clickjacking Prevention

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

روش سوم، بررسی هدرها با curl:

curl -I https://your-site.com/

در خروجی، باید خطوط X-Frame-Options و Content-Security-Policy را ببینید. اگر نمی‌بینید، احتمالاً وب‌سرور یا یک افزونه آن‌ها را حذف کرده است. برای عیب‌یابی جامع‌تر، تست امنیت وب‌سایت را ببینید.

اشتباهات رایج در پیاده‌سازی

  • ارسال فقط X-Frame-Options: مرورگرهای مدرن ممکن است آن را نادیده بگیرند.
  • استفاده از ALLOW-FROM: پشتیبانی نامنظم در مرورگرها.
  • فعال‌سازی روی همه صفحات بدون استثنا: ممکن است برخی افزونه‌ها یا قابلیت‌های داخلی سایت را بشکند.
  • نادیده گرفتن زیردامنه‌ها: در سایت‌های چندزبانه، ممکن است قاب‌بندی داخلی مورد نیاز باشد.
  • تکیه بر افزونه بدون تست: بعضی افزونه‌ها هدرها را روی همه صفحات اعمال می‌کنند و همین باعث تداخل با Google Tag Manager یا ابزارهای تحلیلی می‌شود.
  • فراموش کردن صفحات ورود و پرداخت: این صفحات باید DENY دریافت کنند. برخی از این اشتباهات در اشتباهات امنیتی رایج در وردپرس فهرست شده‌اند.

پرسش‌های پرتکرار درباره Clickjacking Prevention در وردپرس

آیا فعال‌سازی X-Frame-Options می‌تواند قالب سایت را بشکند؟ خیر، مگر اینکه قالب شما به‌طور ناخواسته از iframe برای نمایش محتوای داخلی استفاده کند. در این صورت، SAMEORIGIN بگذارید نه DENY.

آیا CSP می‌تواند با Google Analytics تداخل کند؟ دایرکتیو frame-ancestors فقط بر قاب‌بندی اثر دارد و با اسکریپت‌های تحلیلی کاری ندارد. اما اگر کل CSP را با دایرکتیوهای دیگر فعال کنید، ممکن است نیاز به تنظیم script-src باشد.

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

آیا Clickjacking روی سایت‌های فروشگاهی هم خطرناک است؟ بسیار. مهاجم می‌تواند کاربر را وادار به تأیید سفارش، افزودن محصول یا حتی تأیید پرداخت کند.

چه هدرهایی برای محافظت کامل لازم است؟ حداقل X-Frame-Options و Content-Security-Policy: frame-ancestors. علاوه بر آن، X-Content-Type-Options، Strict-Transport-Security و Referrer-Policy را نیز در نظر بگیرید.

برای درک عمیق‌تر مفاهیم پایه، صفحه Clickjacking در ویکی‌پدیا توضیحات مفیدی دارد.

خط پایان

Clickjacking یک تهدید پنهان اما واقعی است که برخلاف XSS و SQL Injection، کمتر جدی گرفته می‌شود. اما وقتی هدف، پیشخوان وردپرس یا فرم پرداخت باشد، پیامدهای آن می‌تواند فاجعه‌بار باشد. دفاع اصلی، ارسال هدرهای مناسب است و خوشبختانه پیاده‌سازی آن در وردپرس ساده است. اگر تا امروز این هدرها را فعال نکرده‌اید، همین امروز انجام دهید.

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