یک بار مشتری‌ای با لحن سراسیمه زنگ زد و گفت یکی از مدیران سایتش بدون این‌که روی لینک مشکوکی کلیک کند، یک محصول جدید در فروشگاه ثبت شده. اول فکر کردیم هک شده، بعد رمز عبور لو رفته، بعد افزونهٔ مخرب. اما وقتی لاگ‌های دسترسی را بررسی کردیم، دیدیم درخواست ثبت محصول، از IP خودِ مدیر سایت آمده بود. مشکل، نه هک بود و نه رمز لو رفته. مشکل این بود که همان مدیر، در همان سشن مرورگر، یک سایت دیگر را در تب دیگری باز کرده بود که حاوی یک فرم مخفی بود. آن فرم، درخواست ثبت محصول را به سایت مشتری ما فرستاده بود و مرورگر، سشن کاربر لاگین‌شده را همراه آن درخواست به‌طور خودکار ارسال کرده بود. این، دقیقاً همان حمله‌ای است که اسمش CSRF است.

CSRF یا Cross-Site Request Forgery (جعل درخواست از سایت دیگر)، یکی از رایج‌ترین و در عین حال کم‌فهم‌شده‌ترین آسیب‌پذیری‌های وب است. برخلاف XSS که روی اجرای کد مخرب در مرورگر قربانی تمرکز دارد، CSRF با سوءاستفاده از اعتماد سایت به مرورگر، درخواست‌های ناخواسته روی حساب کاربر انجام می‌دهد. توضیح تفصیلی‌تر مفهوم حمله و کلیات دفاع را در CSRF چیست و چگونه از آن جلوگیری کنیم؟ آورده‌ام؛ این مقاله، لایهٔ عملیاتی و میدانی همان موضوع است.

CSRF چیست و در عمل چگونه رخ می‌دهد؟

CSRF به زبان ساده یک سوءاستفاده از اعتماد است: سایت شما به مرورگر کاربر اعتماد می‌کند، چون کاربر خودش لاگین کرده و کوکی سشن دارد. مهاجم این اعتماد را می‌دزدد و از مرورگر همان کاربر، درخواست ناخواسته می‌فرستد. سشن کاربر معتبر است، پس سایت هم قبول می‌کند و عملیات انجام می‌شود.

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

برای درک بهتر، یک سناریوی واقعی که در پروژه‌ای دیدم: یک سایت فروشگاهی ایرانی، صفحهٔ تغییر ایمیل حساب کاربری را بدون توکن CSRF پیاده کرده بود. یک مهاجم با ارسال ایمیلی حاوی تصویر <img src="https://shop.example.com/change-email?email=attacker@evil.com"> به کاربر، کاری کرد که وقتی کاربر ایمیل را باز می‌کند، مرورگر به‌طور خودکار این درخواست را بفرستد. اگر کاربر در آن لحظه در فروشگاه لاگین بود، ایمیل حساب به مهاجم تغییر می‌کرد و بعد از آن می‌توانست رمز را بازیابی کند. تمام این فرآیند در چند ثانیه و بدون این‌که کاربر متوجه شود.

CSRF سوءاستفاده از اعتماد است، نه شکستن رمز. به همین دلیل، برخلاف حمله‌های رمزشکن، دفاع در برابر آن فقط با احراز هویت قوی‌تر حل نمی‌شود؛ باید مکانیزم اختصاصی ضد CSRF داشته باشید.

چرا CSRF خطرناک است حتی وقتی کاربر لاگین است؟

خطر CSRF از سه ویژگی ناشی می‌شود که با هم ترکیب می‌شوند:

ویژگی اول: سشن کاربر معتبر است

سایت شما به درخواستی که از مرورگر کاربر می‌آید اعتماد می‌کند، چون کوکی سشن همراهش هست. سایت نمی‌داند که درخواست از یک تب آلوده آمده یا از دکمه‌ای که کاربر خودش زده. از دید سرور، هر دو یکسان‌اند.

ویژگی دوم: مرورگرها کوکی را خودکار ارسال می‌کنند

پروتکل HTTP و مکانیزم کوکی، کوکی‌های سایت را در همهٔ درخواست‌هایی که به آن دامنه می‌روند به‌طور خودکار ارسال می‌کند، حتی اگر درخواست از یک صفحهٔ کاملاً دیگر آغاز شده باشد. این طراحی اولیه، منبع اصلی آسیب‌پذیری CSRF است.

ویژگی سوم: کاربر متوجه نمی‌شود

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

مکانیزم حمله CSRF در سه گام

برای فهم دقیق دفاع، باید مکانیزم حمله را گام‌به‌گام بدانید:

  1. گام اول — کاربر لاگین می‌کند: کاربر در سایت شما وارد حساب خود می‌شود و کوکی سشن معتبر در مرورگرش ذخیره می‌شود.
  2. گام دوم — مهاجم کاربر را به ارسال درخواست تحریک می‌کند: کاربر یک صفحهٔ آلوده باز می‌کند، روی یک لینک فریبنده کلیک می‌کند یا حتی فقط یک ایمیل حاوی تصویر را باز می‌کند. در تمام این حالت‌ها، مرورگر درخواستی به سایت شما می‌فرستد.
  3. گام سوم — سایت درخواست را قبول می‌کند: چون سشن کاربر معتبر است و درخواست به سایت شما رفته، سایت آن را به‌عنوان درخواست خودِ کاربر می‌پذیرد و عملیات را انجام می‌دهد.

هر سه گام باید با هم وجود داشته باشند تا حمله موفق شود. دفاع در برابر CSRF یعنی شکستن یکی از این سه گام — که در عمل، شکستن گام سوم رایج‌ترین و مؤثرترین راه است.

چه سایت‌هایی در برابر CSRF آسیب‌پذیرند؟

هر سایتی که دارای فرم یا عملیاتی است که بر اساس سشن کاربر انجام می‌شود، در معرض CSRF است. عملیات پرخطر عبارتند از:

  • تغییر رمز عبور یا ایمیل حساب کاربری
  • افزودن یا حذف کاربر مدیر
  • ثبت، ویرایش یا حذف نوشته و محصول
  • ثبت سفارش یا تغییر موجودی
  • تغییر تنظیمات سایت
  • حذف یا تغییر محتواهای مهم
  • اتصال یا قطع اتصال اپلیکیشن‌های شخص ثالث به حساب
  • انتقال وجه یا هر عملیات مالی

در سایت‌های فروشگاهی و انجمن‌های کاربرمحور، دامنهٔ CSRF وسیع‌تر است. به‌طور کلی: اگر یک عملیات، وضعیت سایت را تغییر می‌دهد و بر اساس سشن کاربر انجام می‌شود، باید در برابر CSRF محافظت شود. قواعد کلی‌تر امنیت وب را در امنیت وب چیست و چه اصولی دارد؟ آورده‌ام.

CSRF در وردپرس: نقاط پرخطر پنهان

وردپرس زیرساخت‌های دفاعی خوبی در برابر CSRF دارد، اما این به‌معنی خودکار امن بودن نیست. نقاط پرخطر در وردپرس و پروژه‌های وردپرسی:

نقطه اول: افزونه‌ها و قالب‌های سفارشی

هستهٔ وردپرس از توکن نانس (Nonce) استفاده می‌کند، اما افزونه‌های سفارشی که خارج از این مکانیزم نوشته می‌شوند، پتانسیل آسیب‌پذیری دارند. اگر افزونه‌ای در فرم‌های خود نانس نمی‌گذارد، همان فرم می‌تواند قربانی CSRF شود. روش بررسی امنیت افزونه‌ها در چگونه امنیت قالب و افزونه وردپرس را بررسی کنیم؟ آمده است.

نقطه دوم: فرآیندهای AJAX در پیشخوان

بسیاری از افزونه‌ها برای عملکرد پیشخوان از درخواست‌های AJAX استفاده می‌کنند. اگر این درخواست‌ها با توکن نانس محافظت نشوند، مهاجم می‌تواند از یک صفحهٔ بیرونی، درخواست‌های مدیریتی ارسال کند.

نقطه سوم: فرم‌های سفارشی کاربر

فرم‌های ثبت‌نام، تماس، پروفایل کاربری — هر کدام باید با نانس محافظت شوند. اگر این فرم‌ها در قالب یا افزونه‌ای سفارشی ساخته شده‌اند و از نانس استفاده نمی‌کنند، خطر CSRF جدی است.

نقطه چهارم: عملیات‌های GET مخرب

اگر عملیات حساس (مثل حذف یک نوشته) با درخواست GET پیاده شده باشد، خطر CSRF بسیار بالا می‌رود، چون درخواست GET می‌تواند با یک تصویر یا لینک ساده فرستاده شود. همیشه عملیات مخرب باید با POST انجام شود.

در پروژه‌ای که روی یک فروشگاه ووکامرسی کار می‌کردم، یک افزونهٔ شخص ثالث، endpoint تغییر وضعیت سفارش را با GET پیاده کرده بود. مهاجم می‌توانست با ارسال لینکی به مدیر فروشگاه، تمام سفارش‌های در انتظار را به وضعیت لغو تغییر دهد. این آسیب‌پذیری در نسخهٔ بعدی افزونه اصلاح شد، اما تا آن زمان چند فروشگاه را گرفتار کرده بود.

در وردپرس، نانس یک ابزار دفاعی است، نه یک فرمالیته. هر فرمی که نانس ندارد، یک درِ باز برای CSRF است — چه فرم مدیریتی، چه فرم کاربری.

شناسایی و تست آسیب‌پذیری CSRF

روش شناسایی CSRF در سایت‌های خودتان یا مشتریان:

روش اول: بررسی کد فرم‌ها

هر فرمی که در سایت وجود دارد، بررسی کنید که آیا در آن فیلد نانس یا توکن CSRF وجود دارد یا نه. در وردپرس، این فیلد معمولاً به‌صورت _wpnonce یا با تابع wp_nonce_field() تولید می‌شود. روش دقیق در پیاده‌سازی نانس در فرم‌های سفارشی آمده است.

روش دوم: بررسی درخواست‌های AJAX

در DevTools مرورگر، تب Network را باز کنید و در حین کار با پیشخوان، درخواست‌های AJAX را ببینید. هر درخواست AJAX که به عملیات حساس مربوط است، باید یک فیلد _wpnonce یا معادل آن داشته باشد.

روش سوم: تست دستی

یک فایل HTML ساده بسازید که یک فرم با متد POST به endpoint حساس سایت شما بفرستد و توکن CSRF نداشته باشد. اگر سایت درخواست را قبول کرد، آسیب‌پذیری CSRF تأیید می‌شود. این تست را فقط روی سایت‌های خودتان یا با اجازه انجام دهید؛ تست روی سایت دیگران غیرقانونی است.

روش چهارم: ابزارهای اسکن

ابزارهای اسکن آسیب‌پذیری مثل OWASP ZAP یا Burp Suite می‌توانند به‌طور خودکار آسیب‌پذیری CSRF را تشخیص دهند. مقایسهٔ این ابزارها در اسکنرهای آسیب‌پذیری وب کدامند؟ آمده است.

دفع CSRF: هفت لایه دفاعی عملی

لایه یکم: توکن CSRF در همه فرم‌های حساس

هر فرمی که عملیات حساس انجام می‌دهد، باید یک توکن یکتای مرتبط با سشن کاربر داشته باشد. در وردپرس، این کار با نانس انجام می‌شود که در ادامه مفصلاً توضیح می‌دهم.

لایه دوم: استفاده از POST برای عملیات مخرب

هیچ عملیات تغییری نباید با GET انجام شود. این قاعدهٔ ساده، به‌تنهایی جلوی بسیاری از حملات مبتنی بر تصویر یا لینک را می‌گیرد.

لایه سوم: کوکی SameSite

با اضافه کردن ویژگی SameSite=Lax یا SameSite=Strict به کوکی سشن، مرورگر کوکی را در درخواست‌های cross-site ارسال نمی‌کند. این ویژگی ساده، مؤثرترین دفاع در سطح کوکی است و از سال ۲۰۲۰ در همه مرورگرهای مدرن به‌طور پیش‌فرض فعال است.

لایه چهارم: بررسی هدر Referer و Origin

سرور می‌تواند بررسی کند که درخواست از چه دامنه‌ای آمده. اگر هدر Origin یا Referer به دامنهٔ سایت شما اشاره نکند، درخواست را رد کند. این لایه به‌عنوان دفاع دوم استفاده می‌شود، چون بعضی کاربران ممکن است Referer را غیرفعال کرده باشند.

لایه پنجم: تأیید مجدد برای عملیات حساس

برای عملیات‌های خیلی حساس مثل تغییر رمز عبور یا حذف حساب، از کاربر بخواهید رمز فعلی را دوباره وارد کند. این کار، حتی اگر CSRF انجام شود، مانع تکمیل حمله می‌شود.

لایه ششم: محدود کردن مدت اعتبار سشن

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

لایه هفتم: آموزش و آگاهی کاربران

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

توکن CSRF و نانس وردپرس: مکانیزم دفاع اصلی

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

در فرم، فیلد نانس را اضافه کنید:

<form method="post" action="">
  <?php wp_nonce_field( 'my_action_name', 'my_nonce_field' ); ?>
  <input type="text" name="user_input" />
  <input type="submit" value="ارسال" />
</form>

در سرور، نانس را بررسی کنید:

if ( ! isset( $_POST['my_nonce_field'] ) ||
     ! wp_verify_nonce( $_POST['my_nonce_field'], 'my_action_name' ) ) {
    wp_die( 'درخواست نامعتبر است.' );
}

برای درخواست‌های AJAX، به‌جای wp_nonce_field از wp_create_nonce در PHP و wp_localize_script برای ارسال به جاوااسکریپت استفاده می‌شود. الگوی کامل این پیاده‌سازی در نوشتن کد PHP امن برای وردپرس آمده است.

نکتهٔ مهمی که در پروژه‌ها زیاد دیده‌ام: بعضی توسعه‌دهندگان نانس را فقط در فرم اصلی می‌گذارند ولی در endpointهای AJAX فراموش می‌کنند. این نقطه، یکی از رایج‌ترین حفره‌های CSRF در افزونه‌های وردپرسی است.

تفاوت CSRF با XSS و SQL Injection

این سه حمله اغلب با هم اشتباه گرفته می‌شوند. تفاوت اصلی‌شان:

ویژگیCSRFXSSSQL Injection
هدف اصلیاجرای عملیات روی حساب کاربراجرای کد در مرورگر قربانیدسترسی غیرمجاز به دیتابیس
نقطه حملهفرم‌ها و endpointهای حساسورودی‌های نمایش داده‌شدهورودی‌های کوئری دیتابیس
پیش‌نیازکاربر لاگین باشدکاربر یک صفحه را ببیندورودی بدون فیلتر باشد
دفاع اصلیتوکن نانس، SameSiteEscaping، Content Security PolicyPrepared Statements

XSS و CSRF گاهی با هم ترکیب می‌شوند: اگر یک سایت هم آسیب‌پذیری XSS داشته باشد و هم CSRF، مهاجم می‌تواند اول با XSS توکن CSRF را بدزدد و بعد از آن حمله را کامل کند. به همین دلیل، امنیت باید در همهٔ لایه‌ها یکدست باشد. جزئیات XSS در حملات XSS چیست و چگونه دفع می‌شود؟ و SQL Injection در SQL Injection چیست و چگونه جلوگیری کنیم؟ آمده است.

پاسخ به سؤال‌های رایج درباره CSRF

CSRF چیست به زبان ساده؟

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

آیا افزونه‌های امنیتی وردپرس جلوی CSRF را می‌گیرند؟

افزونه‌های امنیتی مثل Wordfence و Sucuri روی لایه‌هایی مثل فایروال و اسکن بدافزار تمرکز دارند و به‌طور مستقیم CSRF را حل نمی‌کنند. CSRF مسئله‌ای است که باید در کد افزونه‌ها و قالب‌ها با نانس حل شود. مقایسهٔ افزونه‌های امنیتی در بهترین افزونه‌های امنیتی وردپرس آمده است.

چه ویژگی‌ای در کوکی سشن، دفاع در برابر CSRF را آسان‌تر می‌کند؟

ویژگی SameSite در کوکی سشن. با مقدار Lax یا Strict، مرورگر کوکی را در درخواست‌های cross-site ارسال نمی‌کند. این ویژگی از سال ۲۰۲۰ به‌طور پیش‌فرض در همه مرورگرهای مدرن فعال است، اما بهتر است صریحاً تنظیم شود.

چرا وردپرس برای همه عملیات‌های پیشخوان از نانس استفاده نمی‌کند؟

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

آیا CSRF فقط در پیشخوان وردپرس خطرناک است؟

خیر. هر جای سایت که عملیات حساس بر اساس سشن کاربر انجام می‌دهد، در معرض CSRF است. فرم‌های پروفایل کاربری، نظرات، سفارش‌ها، ثبت‌نام‌ها، بازیابی رمز عبور و فرم‌های تماس با پیام‌های ذخیره‌شده، همه در این فهرست قرار می‌گیرند. در فروشگاه‌های ووکامرس، endpointهای تغییر سبد و ثبت سفارش هم باید بررسی شوند.

آیا تغییر رمز عبور، دفاع در برابر CSRF است؟

خیر. تغییر رمز عبور با CSRF ارتباط مستقیم ندارد، چون در CSRF مهاجم رمز را نمی‌داند و از سشن فعال کاربر استفاده می‌کند. رمز قوی در دفاع از سایر حملات مثل Brute Force مهم است، اما در CSRF، توکن نانس و SameSite دفاع اصلی‌اند. راهنمای ترکیبی این دو در چگونه ورود ادمین وردپرس را امن کنیم؟

امنیت فرم‌ها: از کجا شروع کنید

اگر امروز فقط یک کار می‌خواهید انجام دهید، این باشد: سه فرم حساس سایت خودتان را انتخاب کنید — فرم تغییر رمز، فرم ثبت محصول، و فرم ثبت‌نام کاربر. کد هر سه را باز کنید و ببینید نانس دارند یا نه. اگر ندارند، همان روز اضافه کنید. این یک کار پانزده دقیقه‌ای است که معمولاً پنجرهٔ CSRF را در پرخطرترین نقاط سایت می‌بندد.

در گام بعدی، به سراغ فرآیندهای AJAX پیشخوان بروید و بررسی کنید که آیا با نانس محافظت شده‌اند. سپس در سطح سرور، ویژگی SameSite را برای کوکی سشن صریحاً تنظیم کنید. با این سه گام، دفاع CSRF سایت شما در سطح بالاتری قرار می‌گیرد.

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