یک صفحه وب ممکن است آزادانه تصاویر، شیوه نامه ها، اسکریپت ها، iframe ها و ویدیوها را با منشا متقابل جاسازی کند. برخی از درخواستهای بین دامنهای، بهویژه درخواستهای Ajax، بهطور پیشفرض توسط خط مشی امنیتی همان origin ممنوع هستند. CORS روشی را تعریف میکند که در آن مرورگر و سرور میتوانند برای تعیین این که آیا اجازه دادن به درخواست cross-origin ایمن است یا خیر، تعامل داشته باشند. این امکان آزادی و عملکرد بیشتری را نسبت به درخواستهای کاملا یکسان فراهم میکند، اما امنتر از اجازه دادن به همه درخواستهای cross-origin است.
CORS یا اشتراک منابع به صورت متقابل یک سازوکار مبتنی بر HTTP-header است که به سرور اجازه میدهد هر origins (دامنه، scheme یا پورت) را که مرورگر باید از طریق آن اجازه بارگیری منابع به جز منبع خود را بدهد، نشان دهد. هم چنین به سازوکاری متکی است که به وسیله آن مرورگرها یک درخواست «preflight» را به سرور میزبان منبع متقابل می دهند تا بررسی کنند که آیا سرور درخواست واقعی را مجاز می کند یا نه. در این درخواست «preflight»، مرورگر header هایی را می فرستد که نشان دهنده متد HTTP و header هایی است که در درخواست واقعی از آن استفاده می شود.
نمونه ای از یک درخواست متقابل:
کد جاوا اسکریپت frontend استفاده شده در https://domain-a.com از XMLHttpRequest برای فرستادن درخواست از https://domain-b.com/data.json استفاده می کند.
به دلایل امنیتی، مرورگرها درخواستهای HTTP را که به صورت cross-origin (منابع متقابل) هستند و در اسکریپتها قرار دارند، محدود میکنند. برای مثال، XMLHttpRequest و Fetch API از خط مشی به نام same-origin policy پیروی می کنند. این به این معنی است که یک برنامه وب با استفاده از آن APIها فقط می تواند منابع را از همان مبدایی که برنامه بارگیری شده است درخواست کند، مگر این که پاسخ از origin های دیگر شامل هدرهای CORS مناسب باشد.
سازوکار CORS از درخواست های متقابل (cross-origin) ایمن و انتقال داده ها بین مرورگرها و سرورها پشتیبانی می کند. مرورگرهای مدرن از CORS در API هایی مانند XMLHttpRequest یا Fetch برای کاهش خطرات درخواست های HTTP که به صورت cross-origin هستند استفاده می کنند.
همه! به طور خاص، این مقاله برای مدیران وب، توسعه دهندگان سرور و توسعه دهندگان فرانت اند مناسب است. مرورگرهای مدرن، سمت کلاینت اشتراکگذاری crossp-origin، از جمله header ها و اجرای خط مشی را مدیریت میکنند. اما استاندارد CORS به این معنی است که سرورها باید هدرهای request و response جدید را مدیریت کنند.
این استاندارد اشتراک گذاری متقابل (cross-origin) میتواند درخواستهای HTTP متقابل (cross-origin) را برای موارد زیر فعال کند:
استاندارد اشتراکگذاری منابع به صورت Cross-Origin با افزودن هدرهای HTTP کار میکند و به سرورها اجازه میدهد توضیح دهند، کدام منبع مجاز به خواندن آن اطلاعات از یک مرورگر وب هستند. علاوه بر این، برای متدهای درخواست HTTP که میتوانند اثرات جانبی بر روی دادههای سرور ایجاد کنند (به ویژه، متدهای HTTP غیر از GET یا POST با انواع MIME خاص)، این مشخصات ایجاب میکند که مرورگرها درخواست را preflight کنند و متدهای پشتیبانی شده را از سرور درخواست کنند. با متد درخواست HTTP OPTIONS، و سپس، پس از تایید از سرور، درخواست واقعی را فرستاده می شود. سرورها هم چنین میتوانند به کلاینت ها اطلاع دهند که آیا اعتبارنامهها (یعنی credentials مانند کوکیها و احراز هویت HTTP) باید همراه با درخواستها فرستاده شوند.
شکست CORS منجر به خطا می شود، اما به دلایل امنیتی، جزئیات مربوط به خطا برای جاوا اسکریپت در دسترس نیست. تنها چیزی که کد می داند این است که یک خطا رخ داده است. تنها راه برای تعیین اینکه دقیقا چه اشتباهی رخ داده است، نگاه کردن به کنسول مرورگر برای جزئیات بیش تراست.بخشهای بعدی راهبردها را مورد بحث قرار میدهند، و همچنین تفکیک هدرهای HTTP مورد استفاده را ارائه میکنند.
در این جا سه راهبرد را معرفی میکنیم که نشان میدهند چگونه اشتراکگذاری cross-origin کار میکند. همه این مثالها از XMLHttpRequest استفاده میکنند که میتواند درخواستهای cross-origin را در هر مرورگر پشتیبانیکننده ایجاد کنند.
const xhr = new XMLHttpRequest(); const url = 'https://bar.other/resources/public-data/'; xhr.open('GET', url); xhr.onreadystatechange = someHandler; xhr.send();
برخی از درخواست ها CORS preflight را راه اندازی نمی کنند. به آن ها درخواستهای ساده میگویند، اگرچه مشخصات Fetch (که CORS را تعریف میکند) از این اصطلاح استفاده نمیکند. یک درخواست ساده درخواستی است که تمام شرایط زیر را داشته باشد:
توجه: WebKit Nightly و پیشنمایش فناوری Safari محدودیتهای بیشتری را روی مقادیر مجاز در سرصفحههای Accept، Accept-Language و Content-Language اعمال میکنند. اگر هر یک از آن هدرها دارای مقادیر «nonstandard» باشند، WebKit/Safari درخواست را یک «درخواست ساده» نمیداند. این که چه مقادیری WebKit/Safari را «غیر استاندارد» در نظر می گیرند، به جز اشکالاتی که WebKit در زیر آمده اند، هنوز مستند نشده اند:
هیچ مرورگر دیگری این محدودیت های اضافی را اعمال نمی کند زیرا آن ها بخشی از مشخصات نیستند. برای مثال، فرض کنید محتوای وب در https://foo.example میخواهد محتوایی را در دامنه https://bar.other فراخوانی کند. کدی جاوا اسکریپت آن ممکن است مثل زیر باشد:
const xhr = new XMLHttpRequest(); const url = 'https://bar.other/resources/public-data/'; xhr.open('GET', url); xhr.onreadystatechange = someHandler; xhr.send();
این عملیات با استفاده از هدرهای CORS برای مدیریت امتیازات، تبادل ساده ای را بین کلاینت و سرور انجام می دهد:
بیایید ببینیم مرورگر در این مورد چه چیزی را برای سرور می فرستد و ببینیم سرور چگونه پاسخ می دهد:
GET /resources/public-data/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Connection: keep-alive Origin: https://foo.example
هدر note از request ،Origin است که نشان می دهد فراخوانی از این آدرس https://foo.example شده است.
HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 00:23:53 GMT Server: Apache/2 Access-Control-Allow-Origin: * Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: application/xml […XML Data…]
در پاسخ، سرور یک هدر Access-Control-Allow-Origin را با Access-Control-Allow-Origin: * برمی گرداند که به این معنی است که منبع می تواند توسط هر منبعی قابل دسترسی باشد.
Access-Control-Allow-Origin: *
این الگوی هدرهای Origin و Access-Control-Allow-Origin ساده ترین استفاده از پروتکل کنترل دسترسی است. اگر صاحبان منبع در https://bar.other مایلند دسترسی به منبع را فقط به درخواست های https://foo.example محدود کنند، (یعنی هیچ دامنه ای به جز https://foo.example نمی تواند به منبع با روش cross-origin دستیابی داشته باشد) آن گاه خط زیر را ارسال می کنند:
Access-Control-Allow-Origin: https://foo.example
توجه: هنگام پاسخ به درخواست credentialed requests (درخواست های اعتبارسنجی)، سرور باید به جای تعیین علامت "*"، باید یک مبدا در مقدار هدر Access-Control-Allow-Origin مشخص کند.
برخلاف درخواستهای ساده، برای درخواستهای «preflighted»، مرورگر ابتدا یک درخواست HTTP را با استفاده از متد OPTIONS به منبعی در مبدا دیگر ارسال میکند تا تعیین کند آیا درخواست واقعی برای ارسال امن است یا خیر. چنین درخواستهایی با cross-origin به صورت preflighted انجام میشوند زیرا ممکن است پیامدهایی برای دادههای کاربر داشته باشند.در زیر نمونه ای از درخواستی است که از قبل ارسال می شود:
const xhr = new XMLHttpRequest(); xhr.open('POST', 'https://bar.other/resources/post-here/'); xhr.setRequestHeader('X-PINGOTHER', 'pingpong'); xhr.setRequestHeader('Content-Type', 'application/xml'); xhr.onreadystatechange = handler; xhr.send('<person><name>Arun</name></person>');
مثال بالا یک بدنه XML برای ارسال با درخواست POST ایجاد می کند. هم چنین، یک هدر درخواست غیراستاندارد X-PINGOTHER تنظیم شده است. چنین هدرهایی بخشی از HTTP/1.1 نیستند، اما به طور کلی برای برنامه های کاربردی وب مفید هستند. از آن جایی که درخواست از یک Content-Type of application/xml استفاده می کند، و از آن جایی که یک هدر سفارشی تنظیم شده است، این درخواست از preflighted می شود.
توجه: همانطور که در زیر توضیح داده شد، درخواست POST واقعی شامل هدرهای *-Access-Control-Request نمی شود. آن ها فقط برای درخواست OPTIONS مورد نیاز هستند. بیایید به تبادل کامل بین کلاینت و سرور نگاه کنیم. اولین تبادل درخواست/پاسخ preflighte است:
OPTIONS /doc HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Connection: keep-alive Origin: https://foo.example Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER, Content-Type HTTP/1.1 204 No Content Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2 Access-Control-Allow-Origin: https://foo.example Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER, Content-Type Access-Control-Max-Age: 86400 Vary: Accept-Encoding, Origin Keep-Alive: timeout=2, max=100 Connection: Keep-Alive
خطوط 1 - 10 بالا درخواست preflight را با متد OPTIONS نشان می دهد. مرورگر تشخیص می دهد که باید این را بر اساس پارامترهای درخواستی که قطعه کد جاوا اسکریپت در بالا استفاده می کرد ارسال کند تا سرور بتواند پاسخ دهد که آیا ارسال درخواست با پارامترهای درخواست قابل قبول است یا خیر. OPTIONS یک متد HTTP/1.1 است که برای تعیین اطلاعات از سرورها استفاده می شود و روشی امن است، به این معنی که نمی توان از آن برای تغییر منبع استفاده کرد. توجه داشته باشید که همراه با درخواست OPTIONS، دو header درخواست دیگر ارسال می شود (به ترتیب خطوط 9 و 10):
Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER, Content-Type
هدر Access-Control-Request-Method به عنوان بخشی از یک درخواست preflighte به سرور اطلاع می دهد که وقتی درخواست ارسال می شود، این کار را با روش درخواست POST انجام می دهد. هدر Access-Control-Request-* به سرور اطلاع می دهد که وقتی درخواست واقعی ارسال شد، این کار را با هدرهای سفارشی X-PINGOTHER و Content-Type انجام می دهد. اکنون سرور این فرصت را دارد تا تعیین کند که آیا تحت این شرایط می تواند درخواستی را بپذیرد یا خیر.خطوط 13 - 22 در بالا پاسخی است که سرور ارائه می دهد که نشان می دهد متد درخواست POST و هدر درخواست X-PINGOTHER هستند. بیایید نگاهی دقیق تر به خطوط 16-19 بیندازیم:
Access-Control-Allow-Origin: https://foo.example Access-Control-Allow-Methods: POST, GET, OPTIONS Access-Control-Allow-Headers: X-PINGOTHER, Content-Type Access-Control-Max-Age: 86400
سرور با Access-Control-Allow-Origin پاسخ می دهد، https://foo.example، فقط دسترسی به دامنه اصلی درخواست کننده را محدود می کند. همچنین با Access-Control-Allow-Methods پاسخ می دهد، که می گوید POST و GET متد های معتبری برای کوئری کردن از منبع مورد نظر هستند (این هدر شبیه به هدر پاسخ Allow است، اما دقیقا در چارچوب کنترل دسترسی استفاده می شود). سرور هم چنین Access-Control-Allow-Headers را با مقدار "X-PINGOTHER، Content-Type" ارسال می کند و تایید می کند که این هدر ها مجاز هستند تا با درخواست واقعی استفاده شوند. مانند Access-Control-Allow-Methods ،Access-Control-Allow-Headers که لیستی از هدرهای قابل قبول جدا شده با کاما هستند.سرانجام، Access-Control-Max-Age مدت زمانی که پاسخ به درخواست preflight بدون ارسال درخواست preflight دیگر در حافظه پنهان می شود را در چند ثانیه نشان می دهد. مقدار پیش فرض 5 ثانیه است. در مورد حاضر، حداکثر سن 86400 ثانیه (= 24 ساعت) است. توجه داشته باشید که هر مرورگر دارای حداکثر مقدار داخلی است که وقتی Access-Control-Max-Age از آن بیش تر شود اولویت دارد.پس از تکمیل درخواست preflight ، درخواست واقعی ارسال می شود:
POST /doc HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Connection: keep-alive X-PINGOTHER: pingpong Content-Type: text/xml; charset=UTF-8 Referer: https://foo.example/examples/preflightInvocation.html Content-Length: 55 Origin: https://foo.example Pragma: no-cache Cache-Control: no-cache <person><name>Arun</name></person> HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:40 GMT Server: Apache/2 Access-Control-Allow-Origin: https://foo.example Vary: Accept-Encoding, Origin Content-Encoding: gzip Content-Length: 235 Keep-Alive: timeout=2, max=99 Connection: Keep-Alive Content-Type: text/plain [Some XML payload]
همه مرورگرها در حال حاضر از تغییر مسیرهای زیر پس از یک درخواست preflight پشتیبانی نمی کنند. اگر پس از چنین درخواستی تغییر مسیری رخ دهد، برخی از مرورگرها در حال حاضر پیام خطایی مانند زیر را گزارش می کنند:این درخواست بهhttps://example.com/foo هدایت می شود، که برای درخواستهای cross-origin که نیاز به preflight اولیه دارند، مجاز نیست. درخواست نیاز به preflight دارد که به دنبال تغییر مسیرهای cross-origin مجاز نیست.پروتکل CORS در ابتدا به این رفتار نیاز داشت اما متعاقبا تغییر کرد تا دیگر نیازی به آن نباشد. با این حال، همه مرورگرها این تغییر را اعمال نکرده اند، و بنابراین همچنان رفتار مورد نیاز اولیه را نشان می دهند.تا زمانی که مرورگرها به مشخصات فنی دسترسی پیدا نکنند، ممکن است بتوانید با انجام یک یا هر دو مورد زیر این محدودیت را برطرف کنید:
اگر این کار امکان پذیر نیست، راه دیگری این است که:
با این حال، اگر درخواستی است که به دلیل وجود هدر مجوز در درخواست، preflight را راهاندازی میکند، نمیتوانید با استفاده از مراحل بالا، محدودیت را برطرف کنید. و شما نمی توانید به هیچ وجه روی آن کار کنید مگر این که روی سروری که درخواست به آن داده می شود کنترل داشته باشید.
توجه: هنگام ارسال درخواستهای اعتبارسنجی به دامنه دیگری، سیاستهای کوکی شخص ثالث همچنان اعمال میشود. این خط مشی همیشه بدون توجه به تنظیماتی که در این فصل توضیح داده شده در سرور و کلاینت اجرا میشود. جالبترین قابلیتی که هم توسط XMLHttpRequest یا Fetch و CORS در معرض دید قرار میگیرد، توانایی ایجاد درخواستهای «معتبر» است که از کوکیهای HTTP و اطلاعات احراز هویت HTTP آگاه هستند. بهطور پیشفرض، در فراخوانهای XMLHttpRequest یا Fetch، مرورگرها اعتبارنامه ارسال نمیکنند. هنگام فراخوانی، یک فلگ خاص باید روی شی XMLHttpRequest یا سازنده Request تنظیم شود.در این مثال، محتوایی که در ابتدا از https://foo.example بارگیری شده است، یک درخواست GET ساده به منبعی در https://bar.other که کوکی ها را تنظیم می کند، می دهد. محتوای foo.example ممکن است حاوی جاوا اسکریپت مانند این باشد:
POST /doc HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Connection: keep-alive X-PINGOTHER: pingpong Content-Type: text/xml; charset=UTF-8 Referer: https://foo.example/examples/preflightInvocation.html Content-Length: 55 Origin: https://foo.example Pragma: no-cache Cache-Control: no-cache <person><name>Arun</name></person> HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:40 GMT Server: Apache/2 Access-Control-Allow-Origin: https://foo.example Vary: Accept-Encoding, Origin Content-Encoding: gzip Content-Length: 235 Keep-Alive: timeout=2, max=99 Connection: Keep-Alive Content-Type: text/plain [Some XML payload]
خط 7 فلگ XMLHttpRequest را نشان میدهد که باید برای فراخوانی با کوکیها تنظیم شود، یعنی برای مقدار بولی withCredentials . به طور پیش فرض، فراخوانی بدون کوکی انجام می شود. از آن جایی که این یک درخواست ساده GET است، از preflight داده نمی شود، اما مرورگر هر پاسخی را که هدر واقعی Access-Control-Allow-Credentials ندارد را رد می کند و پاسخ را در دسترس محتوای وب فراخوانی قرار نمی دهد.
در این جا یک نمونه تبادل بین مشتری و سرور وجود دارد:
GET /resources/credentialed-content/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Connection: keep-alive Referer: https://foo.example/examples/credential.html Origin: https://foo.example Cookie: pageAccess=2 HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:34:52 GMT Server: Apache/2 Access-Control-Allow-Origin: https://foo.example Access-Control-Allow-Credentials: true Cache-Control: no-cache Pragma: no-cache Set-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMT Vary: Accept-Encoding, Origin Content-Encoding: gzip Content-Length: 106 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain [text/plain payload]
اگرچه خط 10 حاوی کوکی است که برای محتوای https://bar.other در نظر گرفته شده است، اگر bar.other با Access-Control-Allow-Credentials پاسخ نمی دهد (خط 17)، پاسخ نادیده گرفته می شود و در دسترس محتوای وب قرار نمی گیرد.
درخواست های CORS، Preflight هرگز نباید شامل credential باشند. پاسخ به یک درخواست Preflight باید Access-Control-Allow-Credentials: true را مشخص کند تا نشان دهد که درخواست واقعی می تواند با credential ها انجام شود.
توجه: برخی از سرویسهای Authentication سازمانی بر خلاف مشخصات Fetch، مستلزم این هستند که گواهیهای مشتری TLS در درخواستهای preflight ارسال شوند.فایرفاکس 87 اجازه می دهد تا این رفتار ناسازگار با تنظیم اولویت network.cors_preflight.allow_client_cert با true bug 1511151 فعال شود. مرورگرهای مبتنی بر Chromium در حال حاضر همیشه گواهی های سرویس گیرنده TLS را در درخواست های پیش از پرواز CORS ارسال می کنند. (Chrome bug 775438)
هنگام پاسخ به یک درخواست معتبر:
اگر یک درخواست شامل یک credential (معمولا یک هدر کوکی) باشد و پاسخ شامل یک هدر Access-Control-Allow-Origin: * باشد، مرورگر دسترسی به پاسخ را مسدود کرده و یک خطای CORS را در کنسول devtools گزارش میکند. اما اگر یک درخواست شامل یک credential (مانند هدر کوکی) باشد و پاسخ شامل یک منبع واقعی به جای یک علامت باشد (Access-Control-Allow-Origin: https://example.com)، پس مرورگر اجازه دسترسی به پاسخ از مبدا مشخص شده را می دهد.
توجه داشته باشید که کوکیهای تنظیمشده در پاسخهای CORS پیرو خط مشیهای کوکی Third-party هستند. در مثال بالا، صفحه از foo.example بارگیری می شود اما کوکی در خط 20 توسط bar.other ارسال می شود و بنابراین اگر مرورگر کاربر به گونه ای پیکربندی شده باشد که همه کوکی های شخص ثالث را رد کند، ذخیره نمی شود. کوکی در درخواست (خط 10) نیز ممکن است در خط مشیهای عادی کوکی Third-party سرکوب شود. بنابراین، سیاست کوکی اجباری ممکن است قابلیت توضیح داده شده در این فصل را باطل کند و عملا مانع از ارائه درخواستهای اعتباری شما شود.
این بخش هدرهای response (پاسخ) HTTP را که سرورها برای درخواستهای کنترل دسترسی برمیگردانند، همان طور که توسط مشخصات اشتراکگذاری Cross-Origin تعریف شده است، فهرست میکند. بخش قبل یک نمای کلی از این موارد در عمل ارائه می دهد.
یک منبع برگشتی ممکن است یک هدر Access-Control-Allow-Origin با دستور زیر داشته باشد:
Access-Control-Allow-Origin: <origin> | *
Access-Control-Allow-Origin یک مبد واحد را مشخص می کند که به مرورگرها می گوید به آن مبدا اجازه دسترسی به منبع را بدهند. یا در غیر این صورت - برای درخواستهای بدون credential علامت "*" به مرورگرها میگوید که به هر منبعی اجازه دسترسی به منبع را بدهند. به عنوان مثال، برای اجازه دادن به کد از مبدا https://mozilla.org برای دسترسی به منبع، می توانید مشخص کنید:
Access-Control-Allow-Origin: https://mozilla.org Vary: Origin
اگر سرور یک origin یکتا را مشخص کند (که ممکن است به صورت پویا براساس origin درخواست به عنوان بخشی از لیست مجاز تغییر کند) به جای علامت "*"، سرور باید origin را نیز در هدر پاسخ Vary قرار دهد تا به مشتریان نشان دهد که سرور پاسخ می دهد. بر اساس مقدار هدر درخواست origin متفاوت خواهد بود.
هدر Access-Control-Expose-Headers هدرهای مشخص شده را به لیست مجاز اضافه می کند که جاوا اسکریپت (مانند getResponseHeader) در مرورگرها اجازه دسترسی به آن را دارد.
Access-Control-Expose-Headers: <header-name>[, <header-name>]*
برای نمونه داریم:
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
به هدرهای X-My-Custom-Header و X-Another-Custom-Header اجازه می دهد تا در دسترس مرورگر قرار گیرند.
هدر Access-Control-Max-Age نشان می دهد که نتایج یک درخواست preflight چه مدت می تواند ذخیره شود. برای نمونه ای از درخواست preflight ، به نمونه های بالا مراجعه کنید.
Access-Control-Max-Age: <delta-seconds>
پارامتر delta-seconds نشاندهنده تعداد ثانیههایی است که نتایج میتوانند در حافظه پنهان شوند.
هدر Access-Control-Allow-Credentials نشان می دهد که آیا پاسخ به درخواست، زمانی که پرچم Credential دارای مقدار true است قابل نمایش است یا خیر. هنگامی که به عنوان بخشی از پاسخ به درخواست preflight استفاده می شود، نشان می دهد که آیا می توان درخواست واقعی را با استفاده از Credential ها انجام داد یا خیر. توجه داشته باشید که درخواستهای ساده GET از preflight نمیشوند، و بنابراین اگر درخواستی برای منبعی با Credential ارسال شود، اگر این هدر همراه با منبع برگردانده نشود، پاسخ توسط مرورگر نادیده گرفته میشود و به محتوای وب بازگردانده نمیشود.
Access-Control-Allow-Credentials: true
هدر Access-Control-Allow-Methods متد یا متدهای مجاز را هنگام دسترسی به منبع مشخص می کند. این در پاسخ به درخواست preflight استفاده می شود. شرایطی که تحت آن یک درخواست از preflight می شود در بالا مورد بحث قرار گرفته است.
Access-Control-Allow-Methods: <method>[, <method>]*
نمونه ای از درخواست preflight در بالا آورده شده است، از جمله مثالی که این هدر را به مرورگر ارسال می کند.
هدر Access-Control-Allow-Headers در پاسخ به یک درخواست preflight استفاده می شود تا نشان دهد که از کدام هدرهای HTTP می توان هنگام درخواست واقعی استفاده کرد. این هدر پاسخ سمت سرور به هدر Access-Control-Request-Headers مرورگر است.
Access-Control-Allow-Headers: <header-name>[, <header-name>]*
این بخش هدرهایی را فهرست میکند که کلاینت ها ممکن است هنگام صدور درخواستهای HTTP به منظور استفاده از ویژگی اشتراکگذاری cross-origin از آن استفاده کنند. توجه داشته باشید که این هدرها برای شما در هنگام فراخوانی سرورها تنظیم شده است. توسعه دهندگانی که از قابلیت XMLHttpRequest به صورت cross-origin استفاده می کنند، مجبور نیستند هدر درخواست اشتراک گذاری cross-origin را به صورت برنامه ریزی شده تنظیم کنند.
هدر Origin مبدا درخواست دسترسی cross-origin یا درخواست preflight را نشان می دهد.
Origin: <origin>
Origin یک URL است که نشان دهنده سروری است که درخواست از آن آغاز شده است. این شامل هیچ اطلاعات مسیر نیست، فقط نام سرور را شامل می شود.
توجه: مقدار Origin می تواند null باشد.
توجه داشته باشید که در هر درخواست کنترل دسترسی، هدر Origin همیشه ارسال می شود.
متد Access-Control-Request-Method هنگام صدور یک درخواست preflight استفاده می شود تا به سرور اطلاع دهد که در زمان انجام درخواست واقعی از کدام متد HTTP استفاده می شود.
Access-Control-Request-Method: <method>
هدر Access-Control-Request-Headers هنگام صدور یک درخواست preflight استفاده می شود تا به سرور اطلاع دهد که هنگام انجام درخواست واقعی از چه هدرهای HTTP استفاده می شود (مانند setRequestHeader) این هدر سمت مرورگر توسط هدر سمت سرور تکمیلی Access-Control-Allow-Headers پاسخ داده می شود.
Access-Control-Request-Headers: <field-name>[, <field-name>]*
اگر شما نیز از توسعه دهندگان وب باشید با مشکلات CORS آشنا شده اید. در صورتی که با این مفهوم آشنا نیستید حتما مطالعه این مقاله را به شما پیشنهاد می کنم. ما در این مقاله مباحث ابتدایی HTTP را توضیح نخواهیم داد بنابراین داشتن درک صحیح و ساده از عملیات های HTTP برای هضم این مقاله لازم است.
زمانی که ما در حال توسعه front-end هستیم در اکثر اوقات داده ای را نمایش می دهیم که جای دیگری (روی سرور دیگری) قرار دارد. به همین منظور مرورگر باید ابتدا یک درخواست HTTP را به سرور مقصد ارسال کند تا تمام داده های مورد نیاز ما را دریافت کند. ما در اینجا نام فرضی www.mywebsite.com را برای وب سایت خود در نظر می گیریم. آدرس API این وب سایت را نیز api.website.com در نظر می گیریم. زمانی که درخواستی به این API ارسال می شود، داده های ما به صورت JSON برای کاربر (هر کسی که درخواست را ارسال کرده است) برگردانده خواهند شد. ما در حال حاضر روی سایت www.mywebsite.com هستیم اما اگر این بار درخواست خود را به دامنه دیگری مانند www.anotherdomain.com ارسال کنیم چه می شود؟ با اجرای این درخواست خطایی به شکل زیر دریافت می کنیم:
Access to fetched has been blocked by CORS policy
CORS مخفف Cross-origin resource sharing یا به اشتراک گذاری منابع از چند سورس مختلف است. برای درک بهتر CORS باید با Same-Origin Policy شروع کنیم.
مرورگرها و دنیای وب به طوری طراحی شده اند که قانونی به نام same-origin policy را اجرا می کنند. این قانون می گوید مقصد درخواست های ما باید با منبعی که به آن هستیم یکی باشد. زمانی مقصد درخواست و منبع آن یکی نیست که:
به طور مثال تا زمانی که به وب سایت mywebsite.com متصل باشیم هیچ اشکالی ندارد که به منابع آن دسترسی داشته باشیم (مثلا https://mywebsite.com/image1.png) اما نمی توانیم به منابع وب سایت دیگری مانند anotherdomain.com دسترسی داشته باشیم. این مسئله به سادگی در تصویر زیر مشخص است:
شاید از خودتان بپرسید چرا قانون same-origin وجود دارد؟ فرض کنید هکری لینک مخربی را برای شما ارسال کرده باشد. شما با کلیک روی این لینک به وب سایت هکر منتقل می شوید (مثلا www.evilwebsite.com) که در ظاهر وب سایت بدی نیست اما در پشت صحنه یک iframe از وب سایت بانکی شما (مثلا www.bank.com) باز می شود و هکر با استفاده از کوکی هایی که در مرورگر شما است، شما را وارد حسابتان می کند. طبیعتا این مسئله یک رخنه امنیتی بزرگ است و نباید مجاز باشد. قانون same-origin برای جلوگیری از چنین حملاتی ایجاد شده است و می گوید که دسترسی به resource ها باید از همان origin ای باشد که به آن متصل هستیم. با وجود این قانون وب سایت www.evilwebsite.com نمی تواند به www.bank.com دسترسی داشته باشد.
منظور ما از سمت کلاینت همان front-end یا مرورگر است. زمانی که وارد دنیای مرورگرها و front-end می شویم باید بدانید که قانون same-origin policy فقط مربوط به اسکریپت ها می شود اما مرورگر ها آن را بسط دادند تا شامل درخواست های جاوا اسکریپتی نیز بشود بنابراین به صورت پیش فرض ما فقط می توانیم به منابعی دسترسی داشته باشیم که از same-origin (از سایتی که در آن هستیم) باشند:
مسئله اینجاست که ما در مواقع بسیاری نیاز به برقراری ارتباط با origin های دیگر (وب سایت های دیگر) داریم. آیا راهی وجود دارد که بر اساس آن بتوانیم به شکل امن از منابع سایت های دیگر نیز استفاده کنیم؟ بله CORS همان راه حل ما است. برایتان توضیح دادم که CORS مخفف Cross-origin resource sharing یا به اشتراک گذاری منابع از چند سورس مختلف است و از همین نام متوجه می شویم که کار آن چیست. User agent ها (مثلا یک مرورگر یا کتابخانه axios یا هر agent دیگری که از آن برای اتصال به یک سایت استفاده شده است) می توانند از مکانیسم خاصی به نام CORS استفاده کنند تا نوع خاصی از درخواست های cross-origin را ارسال کنند. این عملیات با استفاده از تنظیم header های خاصی در درخواست HTTP شما انجام می شود.
زمانی که می خواهیم یک درخواست Cross-origin (درخواستی به منبع دیگر) را ارسال کنیم، مرورگر شما یک header خاص به نام Origin را به درخواست HTTP اضافه می کند. مقدار این header برابر با منبعی است که درخواست از آن ارسال شده است. سرور این درخواست را دریافت کرده و header هایش را بررسی می کند تا بداند هر درخواست از کجا آمده است.
اگر شما توسعه دهنده سرور هستید باید header های مجموعه Access-Control را به پاسخ های سرور خود اضافه کنید. مرورگرها بر اساس مقدار این دسته از header ها می توانند مشخص کنند که چه نوع درخواست های cross-origin ای مجاز هستند. در صورتی که Access-Control در header شما نباشد، تمام درخواست های cross-origin بلوکه خواهند شد. تعداد header های مربوط به Access-Control بسیار زیاد است اما مرورگر فقط یک header خاص را برای مجاز دانستن درخواست های cross-origin می خواهد و آن هم Access-Control-Allow-Origin می باشد. مقداری که به این header می دهید مشخص خواهد کرد که چه مقصد هایی می توانند به این منبع (سرور ما) درخواست ارسال کنند. به طور مثال اگر قرار است وب سایت https://mywebsite.com به سرور و وب سایت ما (مثلا https://api.mywebsite.com) دسترسی داشته باشد باید آن را به header ذکر شده پاس بدهیم:
حالا اگر درخواستی از سمت https://mywebsite.com ارسال شود می تواند به منابع موجود در https://api.mywebsite.com نیز دسترسی داشته باشد. از این به بعد مرورگر مقدار موجود در Access-Control-Allow-Origin را با مقصد درخواست شما مقایسه می کند و اگر این دو یکی نباشند اجازه ارسال درخواست را نخواهید داشت. شما می توانید این دو حالت را در دو تصویر زیر مشاهده کنید:
در تصویر دوم خطای معروف CORS را مشاهده می کنیم. قسمت دوم این درخواست دقیقا چیزی که ما توضیح دادیم را ذکر می کند:
The 'Access-Control-Allow-Origin' header has a value 'https://www.mywebsite.com' that is not equal to the supplied origin.
در نظر داشته باشید که Access-Control-Allow-Origin می تواند مقدار * را نیز بگیرد که در این صورت تمام درخواست های CORS از هر منبعی مجاز خواهند بود. انجام این کار پیشنهاد نمی شود چرا که خطرات امنیتی خاص خودش را دارد.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.
در این قسمت، به پرسشهای تخصصی شما دربارهی محتوای مقاله پاسخ داده نمیشود. سوالات خود را اینجا بپرسید.