اشتراک منابع متقابل (CORS)

منابع بین‌منبعی را با خیال راحت به اشتراک بگذارید

Mariko Kosaka

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

برنامه‌های وب مدرن اغلب می‌خواهند منابع را از مبدأ دیگری دریافت کنند، به عنوان مثال، بازیابی داده‌های JSON از یک دامنه دیگر یا بارگذاری تصاویر از سایت دیگری در یک عنصر <canvas> . اینها می‌توانند منابع عمومی باشند که باید برای خواندن برای همه در دسترس باشند، اما سیاست same-origin استفاده از آنها را مسدود می‌کند. توسعه‌دهندگان از گذشته از راه‌حل‌هایی مانند JSONP استفاده کرده‌اند.

اشتراک‌گذاری منابع بین مبداهای مختلف (CORS) این مشکل را به روشی استاندارد حل می‌کند. فعال کردن CORS به سرور اجازه می‌دهد تا به مرورگر بگوید که می‌تواند از یک مبدا اضافی استفاده کند.

درخواست منبع در وب چگونه کار می‌کند؟

درخواست و پاسخ
درخواست کلاینت و پاسخ سرور به صورت مصور.

یک مرورگر و یک سرور می‌توانند با استفاده از پروتکل انتقال ابرمتن (HTTP) داده‌ها را از طریق شبکه تبادل کنند. HTTP قوانین ارتباطی بین درخواست‌کننده و پاسخ‌دهنده، از جمله اطلاعات مورد نیاز برای دریافت یک منبع را تعریف می‌کند.

هدر HTTP تبادل پیام بین کلاینت و سرور را انجام می‌دهد و برای تعیین دسترسی استفاده می‌شود. هم درخواست مرورگر و هم پیام پاسخ سرور به یک هدر و یک بدنه تقسیم می‌شوند.

اطلاعاتی در مورد پیام مانند نوع پیام یا کدگذاری پیام. یک هدر می‌تواند شامل اطلاعات متنوعی باشد که به صورت جفت‌های کلید-مقدار بیان می‌شوند. هدر درخواست و هدر پاسخ حاوی اطلاعات متفاوتی هستند.

نمونه سربرگ درخواست

Accept: text/html
Cookie: Version=1

این هدر معادل این است که بگوییم «می‌خواهم در پاسخ HTML دریافت کنم. این یک کوکی است که من دارم.»

نمونه هدر پاسخ

Content-Encoding: gzip
Cache-Control: no-store

این هدر معادل این جمله است که «داده‌های موجود در این پاسخ با gzip کدگذاری شده‌اند. این را ذخیره نکنید.»

بدن

خود پیام. این می‌تواند متن ساده، یک تصویر باینری، JSON، HTML یا بسیاری از قالب‌های دیگر باشد.

CORS چگونه کار می‌کند؟

سیاست same-origin به مرورگر می‌گوید که درخواست‌های cross-origin را مسدود کند. وقتی به یک منبع عمومی از یک منبع متفاوت نیاز دارید، سرور ارائه دهنده منبع به مرورگر می‌گوید که مبدا ارسال کننده درخواست می‌تواند به منبع آن دسترسی داشته باشد. مرورگر این موضوع را به خاطر می‌سپارد و اجازه اشتراک‌گذاری منابع cross-origin را برای آن منبع می‌دهد.

مرحله 1: درخواست کلاینت (مرورگر)

وقتی مرورگر یک درخواست بین مبدایی (cross-origin request) ارسال می‌کند، یک هدر مبدا ( Origin header) با مبدا فعلی (scheme، host و port) اضافه می‌کند.

مرحله ۲: پاسخ سرور

وقتی سروری این هدر را می‌بیند و می‌خواهد اجازه دسترسی بدهد، یک هدر Access-Control-Allow-Origin به پاسخ اضافه می‌کند که مبدا درخواست‌کننده را مشخص می‌کند (یا * برای اجازه دادن به هر مبدایی).

مرحله ۳: مرورگر پاسخ را دریافت می‌کند

وقتی مرورگر این پاسخ را با یک هدر Access-Control-Allow-Origin مناسب می‌بیند، داده‌های پاسخ را با سایت کلاینت به اشتراک می‌گذارد.

اشتراک‌گذاری اعتبارنامه‌ها با CORS

به دلایل حفظ حریم خصوصی، CORS معمولاً برای درخواست‌های ناشناس استفاده می‌شود که در آن‌ها درخواست‌کننده شناسایی نمی‌شود. اگر می‌خواهید هنگام استفاده از CORS که می‌تواند فرستنده را شناسایی کند، کوکی ارسال کنید، باید هدرهای اضافی به درخواست و پاسخ اضافه کنید.

درخواست

همانطور که در مثال زیر آمده است، credentials: 'include' را به گزینه‌های fetch اضافه کنید. این شامل کوکی همراه با درخواست به شرح زیر است:

fetch('https://example.com', {
  mode: 'cors',
  credentials: 'include'
})

پاسخ

Access-Control-Allow-Origin باید روی یک مبدا خاص تنظیم شود (از * استفاده نکنید) و Access-Control-Allow-Credentials باید روی true تنظیم شود.

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true

درخواست‌های پیش از پرواز برای فراخوانی‌های پیچیده HTTP

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

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

  • درخواستی که از روش‌هایی غیر از GET، POST یا HEAD استفاده می‌کند.
  • درخواستی که شامل هدرهایی غیر از Accept ، Accept-Language یا Content-Language باشد.
  • درخواستی که دارای سرآیند Content-Type غیر از application/x-www-form-urlencoded ، multipart/form-data یا text/plain .

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

OPTIONS /data HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: DELETE

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

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, DELETE, HEAD, OPTIONS

پاسخ سرور همچنین می‌تواند شامل یک هدر Access-Control-Max-Age باشد تا مدت زمان ذخیره نتایج پیش از پرواز را بر حسب ثانیه مشخص کند. این به کلاینت اجازه می‌دهد تا چندین درخواست پیچیده را بدون نیاز به تکرار درخواست پیش از پرواز ارسال کند.