درک و رفع گامبهگام خطای cors در برنامههای وب
درک و رفع گامبهگام خطای cors در برنامههای وب
خطای cors یکی از رایجترین موانع در توسعهٔ وب است که هنگام تبادل داده میان منشأهای مختلف رخ میدهد. این راهنمای فنی و عملی شما را قدمبهقدم به سمت تشخیص علت، اصلاح هدرها و راهکارهای تست میبرد تا بدون کاهش امنیت، مشکل را رفع کنید.
خطای cors چیست و چطور کار میکند؟
مرورگرها برای حفاظت از کاربران از سیاستی به نام «هممبدأ» (Same-Origin Policy) استفاده میکنند. وقتی یک اسکریپت از یک منشأ درخواست منابع از منشأ دیگر میفرستد، مرورگر بررسی میکند که پاسخ سرور هدرهای کنترل دسترسی لازم را داشته باشد. در غیر این صورت، مرورگر ارسال یا خواندن پاسخ را محدود میکند و توسعهدهنده با خطای cors مواجه میشود؛ یعنی مشکل از تعامل بین مرورگر و پیکربندی سرور است، نه از خطای شبکه صرف.
اجزای کلیدی
- منشأ (origin): ترکیب پروتکل، دامنه و پورت که درخواست را آغاز میکند.
- هدرهای کنترل دسترسی: Access-Control-Allow-Origin، Access-Control-Allow-Methods، Access-Control-Allow-Headers، Access-Control-Allow-Credentials و Access-Control-Max-Age.
- درخواستهای پیشپرواز (preflight): مرورگر برای برخی درخواستها ابتدا یک درخواست OPTIONS میفرستد تا مجاز بودن روش، هدرها یا ارسال credentialها بررسی شود.
علل شایع وقوع خطای cors
شناخت دقیقترین دلیل، زمان رفع را کوتاه میکند. دلایل معمول عبارتاند از:
- سرور هدر Access-Control-Allow-Origin را نمیفرستد یا مقدار آن با منشأ کلاینت مطابقت ندارد.
- هدرهای روش یا هدرهای سفارشی در پاسخ اعلان نشدهاند (مثلاً Access-Control-Allow-Methods یا Access-Control-Allow-Headers ناقص است).
- پاسخدهی به درخواست OPTIONS انجام نمیشود یا وضعیت/هدرهای مناسب بازگردانده نمیشوند.
- وقتی credential ارسال میشود، مقدار Access-Control-Allow-Origin برابر '*' است که مرورگر آن را قبول نمیکند.
- سرویسهای میانی مانند پروکسی یا CDN هدرهای CORS را بازنویسی یا حذف میکنند.
رفع خطای cors: راهکارهای عملی و امن
برای رفع پایدار خطای cors باید بین دسترسی و امنیت تعادل برقرار کنید. مجموعه اقدامهای زیر در سطوح مختلف معماری کاربردیاند:
- محدوده منشأها را دقیق کنید: بهجای '*'، فهرستی از منشأهای مجاز نگه دارید و فقط آن منشأها را در Access-Control-Allow-Origin بازگردانید.
- روشها و هدرها را مشخص کنید: Access-Control-Allow-Methods و Access-Control-Allow-Headers را مطابق نیاز API تعیین کنید تا مرورگر بداند چه مجازاتی وجود دارد.
- پاسخ به پیشپرواز: برای درخواستهای غیرساده (مثلاً با Content-Type: application/json یا هدرهای سفارشی) یک هندلر OPTIONS بدهید که هدرهای CORS و وضعیت 204 یا 200 بازگرداند.
- ارسال credential: اگر نیاز به کوکی یا توکن دارید، از Access-Control-Allow-Credentials: true استفاده کنید و Origin را دقیق مقداردهی کنید؛ '*' مجاز نیست.
- بررسی لایههای میانی: اطمینان پیدا کنید پراکسی، لودبالانسر یا CDN هدرها را تغییر نمیدهند یا نیاز به تنظیمات اضافی ندارند.
نمونههای عملی هدر
نمونهٔ پاسخ سادهٔ سرور برای یک درخواست موفق:
HTTP/1.1 200 OK
Content-Type: application/json
Access-Control-Allow-Origin: https://client-origin
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, X-Requested-With
{"status":"ok"}
نمونهٔ پاسخ پیشپرواز (OPTIONS):
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://client-origin
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400
مثال کلاینت با fetch
fetch('https://api/endpoint/data', {
method: 'GET',
credentials: 'include' // وقتی کوکی لازم است
})
.then(res => res.json())
.then(data => console.log(data))
.catch(err => console.error('خطا:', err));
نکته: اگر از credentials استفاده میکنید، سرور باید Access-Control-Allow-Credentials: true ارسال کند و Access-Control-Allow-Origin دقیقاً همان منشأ کلاینت باشد.
مشاهده و رفع خطای cors: روند گامبهگام عیبیابی
برای یافتن سریع منشأ مشکل، این چکلیست را دنبال کنید:
- پیام کنسول مرورگر را بخوانید: مرورگرها اغلب بهطور صریح میگویند کدام هدر یا رفتار مفقود است.
- در تب Network پاسخ را بررسی کنید: مطمئن شوید هدرهای Access-Control-* در پاسخ وجود دارند.
- اگر درخواست OPTIONS دیده میشود، مطمئن شوید مسیر مربوطه پاسخ مناسب با هدرها و کد 200/204 میدهد.
- با curl یک درخواست مستقیم ارسال کنید تا پاسخ سرور بدون دخالت مرورگر نمایش داده شود و هدرها را بررسی کنید (نمونهٔ پایین).
- کش مرورگر و لایههای میانی (CDN، پراکسی) را پس از تغییرات پاک کنید و مجدداً تست کنید.
- اگر از سرویسهای میانی استفاده میکنید، از تنظیمات آنها برای نگهداری یا عبور هدرها استفاده کنید.
مثال تست با curl
curl -i -X OPTIONS 'https://api/endpoint/data' \
-H 'Origin: https://client-origin' \
-H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: Content-Type'
خروجی curl هدرهای بازگشتی را نشان میدهد و کمک میکند بفهمید سرور یا لایهٔ میانی چه هدرهایی را ارسال میکند یا حذف میکند.
پیکربندی نمونه برای سناریوهای رایج
در زیر نکات کلی برای سه سناریوی معمول آورده شده؛ پیادهسازی دقیق بسته به سرور یا فریمورک شما متفاوت است:
۱) API عمومی غیرحساس
برای دادههای کاملاً عمومی میتوانید منشأهای محدودی را مجاز کنید یا در صورت بررسی دقیق ریسک از Access-Control-Allow-Origin: * استفاده کنید. با این حال حتی برای دادهٔ عمومی، لاگگذاری و محدودیت نرخ را فراموش نکنید.
۲) API با احراز هویت
اگر توکن یا کوکی استفاده میشود، از Access-Control-Allow-Credentials: true استفاده کنید و Origin را دقیق تنظیم کنید. در کنار CORS، اعتبارسنجی توکن در سرور را هم اجباری کنید.
۳) مسیرهای دارای پیشپرواز
برای مسیرهایی که روشها یا هدرهای غیرساده دارند، یک پاسخ سریع OPTIONS ایجاد کنید که هدرهای لازم و Access-Control-Max-Age را برگرداند تا مرورگر نیاز به ارسال پیشپرواز مکرر نداشته باشد.
ملاحظات امنیتی هنگام رفع خطای cors
باز کردن بیمحابای هدرها میتواند درهای نفوذ را باز کند. چند نکته امنیتی کلیدی:
- فهرست منشأها را محدود نگه دارید؛ پذیرش Origin بهصورت داینامیک بدون تأیید میتواند باعث سوءاستفاده شود.
- کنترل دسترسی سروری را تکمیل کنید: بررسی توکنها، مجوزها و محدودیت نرخ را روی سرور اعمال نمایید.
- اطلاعات حساس را در هدر یا پاسخهای سرویسهایی که برای عموم در دسترس است ارسال نکنید.
- پس از تغییرات، تستهای نفوذ و بازبینی لاگ را برنامهریزی کنید تا رفتار ناخواسته شناسایی شود.
تست خودکار، CI و ابزارهای مفید
برای جلوگیری از بازگشت مشکل در استقرارهای بعدی از اتوماسیون استفاده کنید:
- در مجموعه تستها، سناریوهایی که منشأهای مختلف را شبیهسازی میکنند اضافه کنید تا هدرها و پاسخهای OPTIONS اعتبارسنجی شوند.
- در خط لولهٔ یکپارچگی مداوم (CI)، اسکریپتی بگمارید که درخواستهای نمونه با curl ارسال کند و گزارش هدرها تولید نماید.
- از لاگسرور و هشدار برای شناسایی افزایش ناگهانی درخواستهای CORS-ردشده استفاده کنید.
منابع برای مطالعهٔ بیشتر
برای اطلاعات استاندارد و جزئیات بیشتر میتوانید به مشخصات رسمی مکانیزم CORS مراجعه کنید: مشخصات رسمی CORS. همچنین مستندات سرور خود را برای شیوهٔ افزودن هدرها و رفتار پیشفرض بررسی کنید.
پرسشهای متداول (FAQ)
آیا خطای cors خطای سرور است یا مرورگر؟
خطای cors ناشی از تعامل میان مرورگر و پاسخ سرور است. معمولاً پیکربندی سرور نادرست است اما مرورگر جلوی دسترسی را اعمال میکند؛ بنابراین هم بررسی پیامهای کنسول و هم لاگ سرور لازم است.
آیا استفاده از '*' همیشه راهحل سریع است؟
'*' سادهترین راه برای باز گذاشتن منابع است اما برای اهدافی که احراز هویت یا داده حساس در میان است بسیار ناامن است. بهترین عمل، تعیین منشأهای مجاز و محدود کردن هدرها و روشها است.
چطور بفهمم یک درخواست پیشپرواز میشود؟
درخواستهایی که از روشهای غیرساده (مانند PUT یا DELETE) استفاده میکنند، یا هدرهای سفارشی دارند یا Content-Type غیرساده مانند application/json، معمولاً پیشپرواز میشوند. در تب Network مرورگر میتوانید درخواست OPTIONS را ببینید.
اگر تغییرات را اعمال کردم اما هنوز مشکل وجود دارد چه کنم؟
کش مرورگر و هر لایهٔ میانی (پراکسی، CDN) را پاک کنید، سپس با curl پاسخ سرور را بدون مرورگر بررسی کنید. بررسی لاگها نشان خواهد داد آیا درخواست OPTIONS به سرور رسیده و چگونه پاسخ داده شده است.