CSRF، XSS و CORS؛ سه مفهومی که خیلی وقت‌ها با هم اشتباه گرفته می‌شوند

CSRF، XSS و CORS؛ سه مفهومی که خیلی وقت‌ها با هم اشتباه گرفته می‌شوند

توسعه‌دهنده بک‌اند

در توسعه وب، امنیت فقط به رمزنگاری رمز عبور یا استفاده از HTTPS محدود نمی‌شود

CSRF، XSS و CORS؛ سه مفهومی که خیلی وقت‌ها با هم اشتباه گرفته می‌شوند

صارم توکلی

۱۰ دقیقه مطالعه

۰ نفر

۱۴۰۵/۶/۳۰

CSRF، XSS و CORS؛ سه مفهومی که خیلی وقت‌ها با هم اشتباه گرفته می‌شوند

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

در این میان سه اصطلاح CSRF، XSS و CORS بسیار زیاد شنیده می‌شوند؛ اما یک اشتباه رایج این است که تصور کنیم هر سه، نوعی حمله امنیتی هستند یا مستقیماً یک مشکل مشابه را حل می‌کنند.

در واقع این سه مفهوم ماهیت متفاوتی دارند:

XSS یک آسیب‌پذیری مرتبط با اجرای کد مخرب در Context یک وب‌سایت است.

CSRF یک حمله است که از اعتماد مرورگر و سرور به درخواست‌های کاربر سوءاستفاده می‌کند.

CORS یک مکانیزم امنیتی مرورگر برای کنترل درخواست‌های Cross-Origin است و به‌خودی‌خود یک حمله محسوب نمی‌شود.

درک همین تفاوت اولیه، بخش بزرگی از ابهام‌های امنیت وب را برطرف می‌کند.


XSS چیست؟

XSS یا Cross-Site Scripting زمانی اتفاق می‌افتد که یک مهاجم بتواند محتوایی را وارد یک صفحه وب کند و مرورگر آن محتوا را به‌عنوان کد قابل اجرا تفسیر کند.

برای مثال فرض کنید یک سایت، نام کاربر را مستقیماً در HTML نمایش می‌دهد.

اگر برنامه ورودی کاربر را به‌درستی مدیریت نکند، مهاجم ممکن است به‌جای یک نام معمولی، محتوایی وارد کند که مرورگر آن را به‌عنوان JavaScript پردازش کند.

در این حالت مشکل اصلی این است که:

داده‌ای که باید صرفاً داده باشد، به کد تبدیل شده است.

XSS چه خطری ایجاد می‌کند؟

بسته به نوع آسیب‌پذیری، XSS می‌تواند برای موارد مختلفی استفاده شود؛ از جمله:

  • تغییر محتوای صفحه

  • اجرای JavaScript در Context سایت

  • دستکاری رابط کاربری

  • ارسال درخواست از طرف کاربر

  • دسترسی به داده‌هایی که JavaScript اجازه دسترسی به آن‌ها را دارد

  • سرقت اطلاعات حساس موجود در صفحه یا Local Storage

  • فریب کاربر برای انجام یک عملیات

بنابراین XSS صرفاً به معنی «نمایش یک Alert» نیست. در یک برنامه واقعی، XSS می‌تواند پیامدهای جدی‌تری داشته باشد.


XSS معمولاً چگونه به وجود می‌آید؟

یکی از رایج‌ترین دلایل، قرار دادن داده‌های کنترل‌شده توسط کاربر در HTML بدون Encoding یا Sanitization مناسب است.

برای مثال، تصور کنید یک سیستم کامنت داشته باشیم و محتوای کامنت مستقیماً وارد DOM شود.

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

به همین دلیل در Frontend باید تفاوت بین:

Text

و

HTML

را جدی گرفت.

در React نیز استفاده از APIهایی مانند dangerouslySetInnerHTML باید با دقت بسیار زیادی انجام شود، زیرا در صورت قرار دادن HTML غیرقابل اعتماد، می‌تواند مسیر ایجاد XSS را باز کند.


CSRF چیست؟

CSRF مخفف Cross-Site Request Forgery است.

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

فرض کنید کاربر در یک فروشگاه اینترنتی وارد حساب خود شده است.

مرورگر او یک Session Cookie دارد.

حالا کاربر وارد یک سایت مخرب می‌شود و آن سایت باعث ارسال درخواستی به فروشگاه می‌شود.

اگر سرور فروشگاه صرفاً بر اساس وجود Cookie درخواست را معتبر بداند، ممکن است درخواست را به حساب کاربر نسبت دهد.

نکته مهم اینجاست:

در CSRF، مهاجم لزوماً نیازی ندارد رمز عبور کاربر را بداند.

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


یک مثال ساده از CSRF

فرض کنید یک API برای تغییر ایمیل حساب وجود داشته باشد:

POST /account/change-email

اگر سیستم احراز هویت فقط به Cookie متکی باشد و هیچ مکانیزم ضد-CSRF وجود نداشته باشد، یک سایت دیگر ممکن است تلاش کند مرورگر کاربر را وادار به ارسال چنین درخواستی کند.

در اینجا مهاجم الزاماً پاسخ API را نمی‌بیند.

هدف اصلی می‌تواند این باشد که:

درخواست از طرف مرورگر کاربر ارسال شود و سرور آن را معتبر تلقی کند.

این تفاوت، یکی از مهم‌ترین نکات در درک CSRF است.


CORS چیست؟

CORS مخفف Cross-Origin Resource Sharing است.

برخلاف XSS و CSRF، CORS یک حمله نیست.

CORS مکانیزمی در مرورگر است که مشخص می‌کند یک Origin می‌تواند به منابع Origin دیگری دسترسی داشته باشد یا خیر.

برای مثال:

Frontend:

https://app.example.com

Backend:

https://api.example.com

این دو Origin متفاوت محسوب می‌شوند.

اگر Frontend بخواهد از طریق JavaScript به Backend درخواست ارسال کند، مرورگر قوانین Same-Origin Policy و CORS را بررسی می‌کند.

سرور می‌تواند با Headerهایی مانند:

Access-Control-Allow-Origin

به مرورگر اعلام کند چه Originهایی مجاز به دسترسی به پاسخ هستند.


Origin دقیقاً چیست؟

برای فهم CORS، باید مفهوم Origin را بشناسیم.

Origin از سه بخش اصلی تشکیل می‌شود:

Protocol + Host + Port

برای مثال:

https://example.com:443

اگر یکی از این بخش‌ها تغییر کند، ممکن است Origin متفاوت شود.

مثلاً:

https://example.com

و

http://example.com

Origin یکسانی ندارند.

همچنین:

https://app.example.com

و

https://api.example.com

نیز Origin متفاوتی دارند.

به همین دلیل وقتی در Next.js، React یا هر Frontend دیگری با API جداگانه کار می‌کنیم، بحث CORS اهمیت پیدا می‌کند.


تفاوت اصلی CSRF، XSS و CORS

برای اینکه این سه مفهوم را با هم اشتباه نگیریم، بهتر است سؤال متفاوتی درباره هرکدام مطرح کنیم.

XSS

سؤال اصلی:

آیا مهاجم می‌تواند کد JavaScript خود را در Context سایت اجرا کند؟

مشکل اصلی:

ورودی غیرقابل اعتماد به‌عنوان کد تفسیر می‌شود.


CSRF

سؤال اصلی:

آیا مهاجم می‌تواند مرورگر کاربر را وادار کند یک درخواست ناخواسته به سایت دیگری ارسال کند؟

مشکل اصلی:

اعتماد سرور به درخواست دارای اعتبار احراز هویت کاربر.


CORS

سؤال اصلی:

آیا JavaScript یک Origin می‌تواند به پاسخ یک Origin دیگر دسترسی داشته باشد؟

مشکل اصلی:

کنترل دسترسی Cross-Origin در مرورگر.


آیا CORS جلوی CSRF را می‌گیرد؟

این یکی از مهم‌ترین سوءتفاهم‌هاست.

خیر، CORS را نباید به‌عنوان مکانیزم اصلی جلوگیری از CSRF در نظر گرفت.

CORS عمدتاً روی این موضوع تمرکز دارد که JavaScript یک Origin چه زمانی اجازه دارد پاسخ یک درخواست Cross-Origin را بخواند.

اما CSRF درباره ارسال درخواست ناخواسته است.

ممکن است یک درخواست ارسال شود، حتی در شرایطی که مهاجم نتواند Response آن را بخواند.

بنابراین:

توانایی ارسال Request و توانایی خواندن Response دو موضوع متفاوت هستند.

برای مقابله با CSRF باید از مکانیزم‌های مناسب مانند CSRF Token و تنظیمات صحیح Cookie استفاده کرد.


آیا CORS جلوی XSS را می‌گیرد؟

خیر.

XSS معمولاً در Context همان Origin اتفاق می‌افتد و CORS راهکار اصلی مقابله با آن نیست.

برای کاهش ریسک XSS، مواردی مانند این‌ها اهمیت بیشتری دارند:

  • Output Encoding

  • Sanitization مناسب HTML

  • جلوگیری از تزریق محتوای غیرقابل اعتماد

  • استفاده صحیح از Frameworkهای Frontend

  • Content Security Policy یا CSP

  • مدیریت صحیح داده‌های کاربر

CORS قرار نیست جایگزین این مکانیزم‌ها شود.


آیا XSS می‌تواند به CSRF مرتبط باشد؟

بله؛ اینجا ارتباط مهمی میان این دو مفهوم وجود دارد.

فرض کنید یک سایت در برابر XSS آسیب‌پذیر باشد.

اگر مهاجم بتواند JavaScript دلخواه خود را در Context سایت اجرا کند، ممکن است بتواند درخواست‌هایی را از داخل همان Origin ایجاد کند.

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

به همین دلیل امنیت وب را نباید به چند تنظیم مستقل و جدا از هم محدود کرد.

یک آسیب‌پذیری می‌تواند زنجیره‌ای از آسیب‌پذیری‌ها و پیامدها ایجاد کند.


Same-Origin Policy چه نقشی دارد؟

برای درک ارتباط این سه مفهوم، باید Same-Origin Policy را هم بشناسیم.

Same-Origin Policy یکی از پایه‌های امنیت مرورگر است که محدودیت‌هایی برای تعامل منابع یک Origin با Originهای دیگر ایجاد می‌کند.

CORS در واقع مکانیزمی است که به سرور اجازه می‌دهد در شرایط مشخص، برخی تعاملات Cross-Origin را برای مرورگر مجاز کند.

به بیان ساده:

Same-Origin Policy محدودیت پایه را ایجاد می‌کند.

CORS سازوکاری برای کنترل برخی استثناهای Cross-Origin است.

در حالی که:

XSS و CSRF سناریوهای امنیتی متفاوتی هستند که باید جداگانه مدیریت شوند.


در یک پروژه واقعی چه کار کنیم؟

در پروژه‌هایی مانند React، Next.js، ASP.NET Core یا هر معماری Frontend/Backend جداگانه، امنیت باید در چند لایه بررسی شود.

برای XSS:

  • داده‌های کاربر را بدون بررسی وارد HTML نکنید.

  • از APIهای خطرناک DOM با احتیاط استفاده کنید.

  • HTML غیرقابل اعتماد را قبل از Render شدن Sanitization کنید.

  • در صورت نیاز CSP را پیاده‌سازی کنید.

برای CSRF:

  • از CSRF Token در معماری‌هایی که به آن نیاز دارند استفاده کنید.

  • Cookieها را با تنظیمات مناسب مانند HttpOnly و SameSite پیکربندی کنید.

  • برای عملیات حساس، کنترل‌های سمت سرور را جدی بگیرید.

  • صرفاً به CORS به‌عنوان راهکار CSRF متکی نباشید.

برای CORS:

  • Originهای مجاز را مشخص کنید.

  • در Production از AllowAnyOrigin بدون بررسی معماری استفاده نکنید.

  • در صورت استفاده از Credentialها، تنظیمات Origin و Cookie را دقیق بررسی کنید.

  • فقط Originهایی را مجاز کنید که واقعاً به API نیاز دارند.


یک سناریوی واقعی در Next.js و ASP.NET Core

فرض کنید معماری پروژه به این شکل باشد:

Next.js → ASP.NET Core API

Frontend روی:

https://shop.example.com

و API روی:

https://api.example.com

قرار دارد.

در این معماری احتمالاً با CORS مواجه خواهید شد، زیرا Frontend و Backend Origin یکسانی ندارند.

اما اگر احراز هویت با Cookie انجام شود، موضوع CSRF نیز باید بررسی شود.

از طرف دیگر، اگر در Frontend یا Backend محتوای HTML کاربر بدون Sanitization مناسب Render شود، XSS نیز می‌تواند به یک مسئله مستقل تبدیل شود.

بنابراین یک پروژه می‌تواند هم‌زمان به تنظیمات صحیح CORS، دفاع در برابر CSRF و محافظت در برابر XSS نیاز داشته باشد.


سه اشتباه رایج

اشتباه اول: CORS یک سیستم امنیتی کامل است

CORS فقط بخشی از مدل امنیت مرورگر را مدیریت می‌کند و جایگزین سایر مکانیزم‌های امنیتی نیست.

اشتباه دوم: اگر CORS درست باشد، CSRF نداریم

CORS و CSRF دو مسئله متفاوت هستند.

اشتباه سوم: XSS یعنی فقط اجرای Alert

XSS می‌تواند بسیار فراتر از یک alert() ساده باشد و در شرایط مناسب، امکان اجرای JavaScript در Context سایت را ایجاد کند.


جمع‌بندی

اگر بخواهیم این سه مفهوم را در کوتاه‌ترین حالت ممکن از هم جدا کنیم:

XSS → اجرای کد غیرقابل اعتماد در Context یک سایت

CSRF → وادار کردن مرورگر کاربر به ارسال درخواست ناخواسته

CORS → کنترل دسترسی JavaScript یک Origin به منابع Origin دیگر

بنابراین وقتی در یک پروژه با خطای CORS مواجه می‌شویم، لزوماً با یک حمله امنیتی مواجه نیستیم.

وقتی درباره CSRF صحبت می‌کنیم، مسئله اصلی ارسال درخواست ناخواسته با اعتبار کاربر است.

و وقتی درباره XSS صحبت می‌کنیم، باید به این سؤال پاسخ دهیم که آیا داده غیرقابل اعتماد می‌تواند به کد قابل اجرا تبدیل شود یا خیر.

شناخت دقیق این تفاوت‌ها، به‌خصوص در پروژه‌های مدرن Next.js، React، ASP.NET Core و API-based Architecture، باعث می‌شود مشکلات امنیتی را به‌جای درمان‌های سطحی، از ریشه تحلیل کنیم.