VULN · آسیب‌پذیری‌ها سمت کلاینت متوسط

CSRF — جعل درخواست میان‌سایتی

Cross-Site Request Forgery

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

تیم فنی پی‌هانتر

CSRF چیست و چگونه کار می‌کند؟

CSRF مخفف Cross-Site Request Forgery است. مکانیزم آن به یک ویژگی بنیادی مرورگر تکیه دارد: مرورگر کوکی‌های یک دامنه را به‌صورت خودکار به آن دامنه پیوست می‌کند، بدون توجه به اینکه درخواست از کدام صفحه شروع شده است. اگر برنامه فقط به وجود کوکی نشست اعتماد کند، صفحه‌ای در دامنه‌ی مهاجم می‌تواند درخواستی معتبر به دامنه‌ی هدف بسازد و برنامه آن را به‌عنوان اقدام آگاهانه‌ی کاربر بپذیرد.

سه پیش‌شرط برای بهره‌برداری لازم است:

  1. یک عملیات ارزشمند: تغییر ایمیل، تغییر رمز، انتقال وجه، افزودن کاربر، تغییر تنظیمات امنیتی.
  2. مدیریت نشست مبتنی بر کوکی: برنامه هویت را فقط از کوکی می‌خواند و هیچ چیز دیگری در درخواست لازم نیست. اگر برنامه هدر Authorization بخواهد، CSRF کلاسیک کار نمی‌کند چون مرورگر آن را خودکار نمی‌فرستد.
  3. پارامترهای قابل پیش‌بینی: مهاجم بتواند تمام مقادیر لازم را از قبل بداند یا حدس بزند.

تفاوت کلیدی با XSS: در XSS مهاجم کد را در زمینه‌ی سایت هدف اجرا می‌کند و می‌تواند پاسخ‌ها را بخواند؛ در CSRF مهاجم فقط می‌تواند درخواست را بفرستد و پاسخ را نمی‌بیند. به همین دلیل CSRF ذاتاً یک حمله‌ی «نوشتنی» است. و به همین دلیل هم هر XSS روی دامنه، همه‌ی دفاع‌های CSRF را بی‌اثر می‌کند — چون مهاجم می‌تواند توکن را بخواند.

SameSite دقیقاً چه چیزی را عوض کرد؟

این بخش، پرخطاترین قسمت محتوای فارسی امنیت است. واقعیت به این شکل است:

مرورگررفتار پیش‌فرض وقتی SameSite تعیین نشده
Chromeمحدودیت Lax را به‌صورت پیش‌فرض اعمال می‌کند
Firefoxپیش‌فرض Lax را اعمال نمی‌کند. باگ ردیابی موزیلا (شماره‌ی ۱۶۱۷۶۰۹) با وضعیت RESOLVED WONTFIX بسته شده؛ این قابلیت در Firefox 96 عرضه و به‌دلیل خرابی گسترده‌ی وب بازگردانده شد
Safariپیش‌فرض Lax در معنای SameSite ندارد؛ در عوض کوکی‌های شخص ثالث را از طریق ITP مسدود می‌کند — سازوکاری متفاوت با حالت‌های مرزی متفاوت

مستندات MDN هم با احتیاط می‌نویسد «برخی مرورگرها اگر SameSite تعیین نشده باشد از Lax استفاده می‌کنند» — نه همه.

معنای سه مقدار:

  • Strict — کوکی فقط در درخواست‌های هم‌سایت ارسال می‌شود؛ حتی هنگام کلیک روی لینک از سایت دیگر هم ارسال نمی‌شود (کاربر خارج‌شده به‌نظر می‌رسد).
  • Lax — علاوه بر درخواست‌های هم‌سایت، در درخواست‌های بین‌سایتی که هم پیمایش سطح بالا باشند و هم با متد امن (GET/HEAD/OPTIONS/TRACE) انجام شوند، ارسال می‌شود.
  • None — در همه‌ی درخواست‌ها ارسال می‌شود و صفت Secure اجباری است.
پنجره‌ی «Lax + POST»

وقتی Lax به‌عنوان پیش‌فرض اعمال می‌شود، کروم نسخه‌ی سهل‌گیرانه‌تری به کار می‌برد که کوکی را در درخواست‌های POST بین‌سایتی هم می‌فرستد، به‌شرطی که کوکی حداکثر دو دقیقه پیش تنظیم شده باشد. Chromium این را «مداخله‌ی موقتی» توصیف کرده که در آینده حذف خواهد شد. اینکه آیا هم‌اکنون حذف شده یا نه از منابع رسمی روشن نیست — بنابراین در تست نفوذ باید وجودش را آزمود، نه فرض کرد که هست یا نیست.

چرا SameSite=Lax حمله را غیرممکن نمی‌کند

حتی در مرورگری که Lax را اعمال می‌کند، این مسیرها باز می‌مانند:

  • عملیات وضعیت‌تغییردهنده روی GET. Lax صراحتاً پیمایش GET را مجاز می‌داند. هر اندپوینتی مثل /account/delete?id=… که با GET کار می‌کند، کاملاً قابل بهره‌برداری است.
  • پارامتر Method Override. فریم‌ورک‌هایی که _method=POST یا هدر X-HTTP-Method-Override را می‌پذیرند، اجازه می‌دهند یک درخواست GET اثر POST داشته باشد و هم‌زمان قید Lax را برآورده کند.
  • Gadget تغییر مسیر سمت کلاینت. اگر خودِ سایت هدف تغییر مسیری را با جاوااسکریپت انجام دهد، درخواست حاصل از دید مرورگر یک درخواست هم‌سایت عادی به‌نظر می‌رسد.
  • زیردامنه‌های خواهر. این مهم‌ترین نکته است: SameSite بر پایه‌ی دامنه‌ی قابل ثبت است، نه Origin. یعنی a.example.com و b.example.com از نظر SameSite «هم‌سایت» محسوب می‌شوند. یک XSS یا Open Redirect روی هر زیردامنه‌ای، تمام حفاظت SameSite را خنثی می‌کند.
باور غلط رایج

«همه‌ی مرورگرهای مدرن پیش‌فرض SameSite=Lax دارند، پس CSRF حل شده است.» غلط است. کروم چنین می‌کند؛ فایرفاکس نمی‌کند و باگ مربوطه در موزیلا با وضعیت WONTFIX بسته شده. سافاری هم سازوکار متفاوتی (مسدودسازی کوکی شخص ثالث در ITP) دارد. مهم‌تر از آن، SameSite یک رفتار مرورگر است نه یک کنترل سمت سرور: شما در حال اتکا به انتخاب و نسخه‌ی مرورگر کاربر هستید. توکن CSRF سمت سرور همچنان الزامی است.

یک تصحیح اصطلاحی هم لازم است: SameSite درخواست‌های بین‌سایتی را محدود می‌کند، نه بین‌مبدأیی. a.example.com به b.example.com بین‌مبدأ (cross-origin) است اما هم‌سایت (same-site) — و SameSite هیچ اثری بر آن ندارد. این تمایز را با CORS که واقعاً مبدأمحور است اشتباه نگیرید.

چگونه در تست نفوذ کشف می‌شود

روال عملی:

  1. فهرست عملیات وضعیت‌تغییردهنده: تغییر ایمیل و رمز، تغییر تنظیمات دو عاملی، افزودن/حذف کاربر، انتقال وجه، تغییر آدرس تحویل، اتصال حساب‌های خارجی.
  2. بررسی صفات کوکی در پنل Application مرورگر یا در پاسخ سرور: آیا SameSite صراحتاً تعیین شده؟ آیا HttpOnly و Secure هستند؟ آیا پیشوند __Host- استفاده شده؟
  3. حذف یا خراب‌کردن توکن: پارامتر توکن را حذف کنید، مقدارش را خالی بگذارید، مقدار یک کاربر دیگر را بگذارید، یا فقط یک کاراکترش را عوض کنید. الگوهای معیوب رایج: توکن فقط وقتی بررسی می‌شود که وجود داشته باشد؛ توکن به نشست مقید نیست؛ توکن روی GET بررسی نمی‌شود.
  4. تغییر متد: اگر عملیات با POST است، همان را با GET یا با _method امتحان کنید.
  5. آزمون در فایرفاکس: اگر سرور SameSite را صراحتاً تعیین نکرده، بهره‌برداری را در فایرفاکس بیازمایید — نتیجه ممکن است با کروم متفاوت باشد.
  6. بررسی زیردامنه‌ها: فهرست زیردامنه‌ها را با subfinder استخراج کنید؛ هر XSS یا تغییر مسیر باز روی یک زیردامنه، سطح حمله‌ی CSRF را باز می‌کند.

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

نمونه‌ی فنی و نگاشت به استانداردها

شکل کلاسیک اثبات مفهوم — یک فرم که به‌صورت خودکار ارسال می‌شود:

<form action="https://app.example.com/account/email"
      method="POST">
  <input name="email" value="attacker@example.net">
</form>
<script>document.forms[0].submit()</script>

و شکل GET که حتی با Lax هم کار می‌کند و به یک صفحه‌ی HTML هم نیاز ندارد:

<img src="https://app.example.com/account/delete?confirm=1">

نگاشت به استانداردها

  • OWASP Top 10:2025: CSRF زیر دسته‌ی A01 — Broken Access Control قرار دارد. در نسخه‌ی ۲۰۱۳ دسته‌ی مستقل بود و امروز نیست، اما همچنان یک یافته‌ی رایج است.
  • CWE-352 — Cross-Site Request Forgery. در فهرست ۲۰۲۵ CWE Top 25 رتبه‌ی سوم را دارد؛ یعنی برخلاف تصور «حل‌شده بودن»، همچنان یکی از پرتکرارترین و پرآسیب‌ترین ضعف‌های ثبت‌شده است.
  • WSTG-SESS: آزمون CSRF یکی از نه آزمون بخش مدیریت نشست راهنمای آزمون OWASP است.

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

آیا با SameSite دیگر به توکن CSRF نیاز نداریم؟

نیاز دارید. SameSite یک رفتار مرورگر است، نه یک کنترل سمت سرور؛ اتکا به آن یعنی اتکا به مرورگر و نسخه‌ای که کاربر انتخاب کرده. فایرفاکس پیش‌فرض Lax را اعمال نمی‌کند، عملیات مبتنی بر GET حتی با Lax قابل سوءاستفاده‌اند، و زیردامنه‌های خواهر از نظر SameSite هم‌سایت محسوب می‌شوند. توکن هم‌زمان‌ساز سمت سرور همچنان الزامی است.

آیا فایرفاکس واقعاً پیش‌فرض SameSite=Lax ندارد؟

ندارد. باگ ردیابی موزیلا با شناسه‌ی ۱۶۱۷۶۰۹ با وضعیت RESOLVED WONTFIX بسته شده است. این قابلیت در Firefox 96 عرضه شد اما به‌دلیل خرابی گسترده‌ی سایت‌ها بازگردانده و غیرفعال شد. تنظیم مربوطه در نسخه‌ی انتشار خاموش است. بنابراین برنامه‌ای که SameSite را صراحتاً تعیین نکرده و توکن CSRF ندارد، امروز در فایرفاکس قابل بهره‌برداری است.

اگر از JWT در هدر Authorization استفاده کنم، CSRF ندارم؟

در حالت کلاسیک بله، چون مرورگر هدر Authorization را خودکار ضمیمه نمی‌کند و مهاجم نمی‌تواند آن را از سایت خودش تنظیم کند. اما اگر همان JWT را در کوکی نگه دارید، دقیقاً همان سطح حمله برمی‌گردد. توجه کنید که نگهداری توکن در localStorage هم مشکل CSRF را با مشکل بزرگ‌تر «خواندنی بودن توسط XSS» عوض می‌کند.

CSRF در OWASP Top 10 کجاست؟

در نسخه‌ی ۲۰۲۵ دسته‌ی مستقلی ندارد و ذیل A01 کنترل دسترسی شکسته قرار می‌گیرد؛ شناسه‌ی CWE آن ۳۵۲ است. نکته‌ی مهم اینکه CWE-352 در فهرست ۲۰۲۵ CWE Top 25 رتبه‌ی سوم را دارد، یعنی از نظر داده‌ی واقعی هنوز بسیار پرتکرار است.

پیشگیری / رفع

به ترتیب اثربخشی:

  1. الگوی توکن هم‌زمان‌ساز (Synchronizer Token). توکنی به‌ازای هر نشست، غیرقابل پیش‌بینی، مقیدشده به نشست، و اعتبارسنجی‌شده در سمت سرور برای هر درخواست وضعیت‌تغییردهنده. این هنوز استاندارد طلایی است و مستقل از رفتار مرورگر کار می‌کند.
  2. تعیین صریح SameSite. مقدار Lax را (یا Strict برای کوکی‌های پرارزش) خودتان بنویسید و به پیش‌فرض مرورگر تکیه نکنید؛ این کار رفتار را در کروم و فایرفاکس یکسان می‌کند.
  3. برای APIها: یک هدر سفارشی الزامی کنید — فرم HTML بین‌سایتی نمی‌تواند هدر سفارشی بفرستد و درخواست را وارد مسیر Preflight می‌کند. به‌علاوه Origin یا Sec-Fetch-Site: same-origin را در سمت سرور راستی‌آزمایی کنید.
  4. هیچ عملیات وضعیت‌تغییردهنده‌ای روی GET نگذارید. این یک قاعده‌ی طراحی است، نه یک تنظیم.
  5. پیشوند __Host- برای کوکی نشست، تا زیردامنه‌ها نتوانند کوکی را تزریق یا بازنویسی کنند.
  6. تأیید مجدد برای عملیات حساس: درخواست رمز فعلی هنگام تغییر ایمیل یا رمز عبور — هم CSRF و هم سوءاستفاده از نشست ربوده‌شده را کاهش می‌دهد.
  7. رفع هر XSS با اولویت بالا. تا وقتی XSS روی دامنه یا زیردامنه‌ها وجود دارد، هیچ دفاع CSRF کامل نیست.

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

→ بازگشت به دانشنامه
PUT IT TO THE TEST

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

تیم پی‌هانتر با دیدِ یک مهاجم واقعی، این آسیب‌پذیری‌ها و ده‌ها مورد دیگر را روی دارایی‌های شما می‌سنجد.