--- title: Cross-Origin Resource Sharing (CORS) slug: Web/HTTP/CORS tags: - AJAX - CORS - HTTP - Безпека translation_of: Web/HTTP/CORS ---
Cross-Origin Resource Sharing ({{Glossary("CORS")}}, перехресний обмін ресурсами) — це механізм, що за допомогою {{Glossary("HTTP")}}-заголовків дає {{Glossary("Browser", "переглядачеві")}} дозвіл завантажувати ресурси з певного джерела на запит web-застосунка, отриманого з відмінного джерела. Web-застосунок виконує перехресний HTTP-запит коли потребує ресурсів з джерела (домен, протокол чи порт), відмінного від його власного.
Приклад перехресного запиту: JavaScript-код web-застосунка, розміщеного на http://domain-a.com
, намагається за допомогою {{domxref("XMLHttpRequest", "AJAX")}}-запиту отримати http://api.domain-b.com/data.json
.
З міркувань безпеки, web-переглядачі припиняють всі перехресні HTTP-запити, здійснені кодом скриптів. Наприклад, XMLHttpRequest
і Fetch API дотримуються правила одного джерела. Це означає, що web-застосунок, отриманий з певного джерела, не може виконувати запити до HTTP-ресурсів з відмінного джерела (хіба якщо відповідь, що з нього надходить, міститиме належні CORS-заголовки).
Механізм CORS уможливлює безпечні перехресні запити та передання даних між web-переглядачами та web-серверами. Сучасні web-переглядачі запроваджують підтримку CORS до API, як-от XMLHttpRequest
або Fetch API, щоб зробити виконання перехресних HTTP-запитів якнайбезпечнішим.
Для кожного, поза сумнівом.
А саме для web-адміністраторів, а також розробників серверних та клієнських застосунків. Сучасні переглядачі запроваджують підтримку CORS з клієнтського боку (зокрема, обробку заголовків та обмеження неправомірних запитів), проте цей новий стандарт потребує, щоб сервер обробляв нові запити й додавав належні заголовки до відповідей. Докладніше про це оповідає стаття «перехресні запити з погляду сервера» для серверних розробників (зі зразками PHP-коду).
Цей стандарт покликаний дозволити міжсайтові HTTP-запити для:
@font-face
в CSS), тож сервер, який розміщує TrueType-шрифти, надає обмежений доступ на їх завантаження лише певній множині сайтів;Ця стаття описує перехресний обмін ресурсами взагалі та окремі HTTP-заголовки, що для цього необхідні.
Стандарт перехресного обміну ресурсами працює за допомогою додавання нових HTTP заголовків, що дозволять серверу описати набір витоків, які мають дозвіл на читання інформації використовуючи веб-браузер. На додаток, для HTTP методів запиту, що можуть спричини побічний еффект на серверні дані (в особливості, для HTTP методів, окрім {{HTTPMethod("GET")}}, або для {{HTTPMethod("POST")}} використання із певним MIME types), специфікація передбачає, що браузерам "попередньо переглядають" запити, вимагають підтримуваних методів з сервера за допомогою HTTP {{HTTPMethod("OPTIONS")}} методів запиту, а потім після "схвалення" з сервера, надсилає фактичний запит методом фактичного запиту HTTP. Сервер також може повідомляти клієнтів чи "credentials" (включаючи Куки і HTTP Аутентифікаційні дані) повинні бути відправлені із запитом.
У наступних розділах обговорюються сценарії, а також надається розбивка використовуваних заголовків HTTP.
Тут ми представляємо три сценарії, які ілюструють, як працює перехресне походження ресурсів. У всіх цих прикладах використовується об’єкт {{domxref ("XMLHttpRequest")}}, який можна використовувати для виклику між сайтів у будь-якому підтримуваному браузері.
Фрагменти JavaScript, що містяться в цих розділах (і запущені екземпляри серверного коду, який правильно обробляє ці запити на різних веб-сайтах), можна знайти "в дії" за адресою http://arunranga.com/examples/access-control/, і буде робота в браузерах, які підтримують крос-сайт {{domxref ("XMLHttpRequest")}}.
Обговорення міжпохідного обміну ресурсами з точки зору сервера (включаючи фрагменти коду PHP) можна знайти в статті управління доступом на стороні сервера (CORS).
Some requests don’t trigger a CORS preflight. Those are called “simple requests” in this article, though the {{SpecName('Fetch')}} spec (which defines CORS) doesn’t use that term. A request that doesn’t trigger a CORS preflight—a so-called “simple request”—is one that meets all the following conditions:
DPR
Save-Data
Viewport-Width
Width
application/x-www-form-urlencoded
multipart/form-data
text/plain
For example, suppose web content on domain http://foo.example
wishes to invoke content on domain http://bar.other
. Code of this sort might be used within JavaScript deployed on foo.example:
var invocation = new XMLHttpRequest(); var url = 'http://bar.other/resources/public-data/'; function callOtherDomain() { if(invocation) { invocation.open('GET', url, true); invocation.onreadystatechange = handler; invocation.send(); } }
This will lead to a simple exchange between the client and the server, using CORS headers to handle the privileges:
Let us look at what the browser will send to the server in this case, and let's see how the server responds:
GET /resources/public-data/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre 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 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive Referer: http://foo.example/examples/access-control/simpleXSInvocation.html Origin: http://foo.example HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 00:23:53 GMT Server: Apache/2.0.61 Access-Control-Allow-Origin: * Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: application/xml [XML Data]
Lines 1 - 10 are headers sent. The main HTTP request header of note here is the {{HTTPHeader("Origin")}} header on line 10 above, which shows that the invocation is coming from content on the domain http://foo.example
.
Lines 13 - 22 show the HTTP response from the server on domain http://bar.other
. In response, the server sends back an {{HTTPHeader("Access-Control-Allow-Origin")}} header, shown above in line 16. The use of the {{HTTPHeader("Origin")}} header and of {{HTTPHeader("Access-Control-Allow-Origin")}} show the access control protocol in its simplest use. In this case, the server responds with a Access-Control-Allow-Origin: *
which means that the resource can be accessed by any domain in a cross-site manner. If the resource owners at http://bar.other
wished to restrict access to the resource to requests only from http://foo.example
, they would send back:
Access-Control-Allow-Origin: http://foo.example
Note that now, no domain other than http://foo.example
(identified by the ORIGIN: header in the request, as in line 10 above) can access the resource in a cross-site manner. The Access-Control-Allow-Origin
header should contain the value that was sent in the request's Origin
header.
Unlike “simple requests” (discussed above), "preflighted" requests first send an HTTP request by the {{HTTPMethod("OPTIONS")}} method to the resource on the other domain, in order to determine whether the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data.
In particular, a request is preflighted if any of the following conditions is true:
DPR
Save-Data
Viewport-Width
Width
application/x-www-form-urlencoded
multipart/form-data
text/plain
The following is an example of a request that will be preflighted.
var invocation = new XMLHttpRequest(); var url = 'http://bar.other/resources/post-here/'; var body = '<?xml version="1.0"?><person><name>Arun</name></person>'; function callOtherDomain(){ if(invocation) { invocation.open('POST', url, true); invocation.setRequestHeader('X-PINGOTHER', 'pingpong'); invocation.setRequestHeader('Content-Type', 'application/xml'); invocation.onreadystatechange = handler; invocation.send(body); } } ......
In the example above, line 3 creates an XML body to send with the POST
request in line 8. Also, on line 9, a "customized" (non-standard) HTTP request header is set (X-PINGOTHER: pingpong
). Such headers are not part of the HTTP/1.1 protocol, but are generally useful to web applications. Since the request uses a Content-Type of application/xml
, and since a custom header is set, this request is preflighted.
(Note: as described below, the actual POST request does not include the Access-Control-Request-* headers; they are needed only for the OPTIONS request.)
Let's take a look at the full exchange between client and server. The first exchange is the preflight request/response:
OPTIONS /resources/post-here/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre 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 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive Origin: http://foo.example Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER, Content-Type HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://foo.example Access-Control-Allow-Methods: POST, GET Access-Control-Allow-Headers: X-PINGOTHER, Content-Type Access-Control-Max-Age: 86400 Vary: Accept-Encoding, Origin Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain
Once the preflight request is complete, the real request is sent:
POST /resources/post-here/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre 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 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive X-PINGOTHER: pingpong Content-Type: text/xml; charset=UTF-8 Referer: http://foo.example/examples/preflightInvocation.html Content-Length: 55 Origin: http://foo.example Pragma: no-cache Cache-Control: no-cache <?xml version="1.0"?><person><name>Arun</name></person> HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:40 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://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 GZIP'd payload]
Lines 1 - 12 above represent the preflight request with the {{HTTPMethod("OPTIONS")}} method. The browser determines that it needs to send this based on the request parameters that the JavaScript code snippet above was using, so that the server can respond whether it is acceptable to send the request with the actual request parameters. OPTIONS is an HTTP/1.1 method that is used to determine further information from servers, and is a {{Glossary("safe")}} method, meaning that it can't be used to change the resource. Note that along with the OPTIONS request, two other request headers are sent (lines 10 and 11 respectively):
Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER, Content-Type
The {{HTTPHeader("Access-Control-Request-Method")}} header notifies the server as part of a preflight request that when the actual request is sent, it will be sent with a POST
request method. The {{HTTPHeader("Access-Control-Request-Headers")}} header notifies the server that when the actual request is sent, it will be sent with a X-PINGOTHER
and Content-Type custom headers. The server now has an opportunity to determine whether it wishes to accept a request under these circumstances.
Lines 14 - 26 above are the response that the server sends back indicating that the request method (POST
) and request headers (X-PINGOTHER
) are acceptable. In particular, let's look at lines 17-20:
Access-Control-Allow-Origin: http://foo.example Access-Control-Allow-Methods: POST, GET Access-Control-Allow-Headers: X-PINGOTHER, Content-Type Access-Control-Max-Age: 86400
The server responds with Access-Control-Allow-Methods
and says that POST
and GET
are viable methods to query the resource in question. Note that this header is similar to the {{HTTPHeader("Allow")}} response header, but used strictly within the context of access control.
The server also sends Access-Control-Allow-Headers
with a value of "X-PINGOTHER, Content-Type
", confirming that these are permitted headers to be used with the actual request. Like Access-Control-Allow-Methods
, Access-Control-Allow-Headers
is a comma separated list of acceptable headers.
Finally, {{HTTPHeader("Access-Control-Max-Age")}} gives the value in seconds for how long the response to the preflight request can be cached for without sending another preflight request. In this case, 86400 seconds is 24 hours. Note that each browser has a maximum internal value that takes precedence when the Access-Control-Max-Age
is greater.
Most browsers currently don’t support following redirects for preflighted requests. If a redirect occurs for a preflighted request, most current browsers will report an error message such as the following.
The request was redirected to 'https://example.com/foo', which is disallowed for cross-origin requests that require preflight
Request requires preflight, which is disallowed to follow cross-origin redirect
The CORS protocol originally required that behavior but was subsquently changed to no longer require it. However, most browsers have not yet implemented the change and still exhibit the behavior that was originally required.
So until browsers catch up with the spec, you may be able to work around this limitation by doing one or both of the following:
But if it’s not possible to make those changes, then another way that may be possible is to this:
However, if the request is one that triggers a preflight due to the presence of the `Authorization` header in the request, you won’t be able to work around the limitation using the steps above. And you won’t be able to work around it at all unless you have control over the server the request is being made to.
The most interesting capability exposed by both {{domxref("XMLHttpRequest")}} or Fetch and CORS is the ability to make "credentialed" requests that are aware of HTTP cookies and HTTP Authentication information. By default, in cross-site {{domxref("XMLHttpRequest")}} or Fetch invocations, browsers will not send credentials. A specific flag has to be set on the {{domxref("XMLHttpRequest")}} object or the {{domxref("Request")}} constructor when it is invoked.
In this example, content originally loaded from http://foo.example
makes a simple GET request to a resource on http://bar.other
which sets Cookies. Content on foo.example might contain JavaScript like this:
var invocation = new XMLHttpRequest(); var url = 'http://bar.other/resources/credentialed-content/'; function callOtherDomain(){ if(invocation) { invocation.open('GET', url, true); invocation.withCredentials = true; invocation.onreadystatechange = handler; invocation.send(); } }
Line 7 shows the flag on {{domxref("XMLHttpRequest")}} that has to be set in order to make the invocation with Cookies, namely the withCredentials
boolean value. By default, the invocation is made without Cookies. Since this is a simple GET
request, it is not preflighted, but the browser will reject any response that does not have the {{HTTPHeader("Access-Control-Allow-Credentials")}}: true
header, and not make the response available to the invoking web content.
Here is a sample exchange between client and server:
GET /resources/access-control-with-credentials/ HTTP/1.1 Host: bar.other User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre 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 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive Referer: http://foo.example/examples/credential.html Origin: http://foo.example Cookie: pageAccess=2 HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:34:52 GMT Server: Apache/2.0.61 (Unix) PHP/4.4.7 mod_ssl/2.0.61 OpenSSL/0.9.7e mod_fastcgi/2.4.2 DAV/2 SVN/1.4.2 X-Powered-By: PHP/5.2.6 Access-Control-Allow-Origin: http://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]
Although line 11 contains the Cookie destined for the content on http://bar.other
, if bar.other did not respond with an {{HTTPHeader("Access-Control-Allow-Credentials")}}: true
(line 19) the response would be ignored and not made available to web content.
When responding to a credentialed request, the server must specify an origin in the value of the Access-Control-Allow-Origin
header, instead of specifying the "*
" wildcard.
Because the request headers in the above example include a Cookie
header, the request would fail if the value of the Access-Control-Allow-Origin
header were "*". But it does not fail: Because the value of the Access-Control-Allow-Origin
header is "http://foo.example
" (an actual origin) rather than the "*
" wildcard, the credential-cognizant content is returned to the invoking web content.
Note that the Set-Cookie
response header in the example above also sets a further cookie. In case of failure, an exception—depending on the API used—is raised.
Note that cookies set in CORS responses are subject to normal third-party cookie policies. In the example above, the page is loaded from foo.example
, but the cookie on line 22 is sent by bar.other
, and would thus not be saved if the user has configured their browser to reject all third-party cookies.
This section lists the HTTP response headers that servers send back for access control requests as defined by the Cross-Origin Resource Sharing specification. The previous section gives an overview of these in action.
A returned resource may have one {{HTTPHeader("Access-Control-Allow-Origin")}} header, with the following syntax:
Access-Control-Allow-Origin: <origin> | *
The origin
parameter specifies a URI that may access the resource. The browser must enforce this. For requests without credentials, the server may specify "*" as a wildcard, thereby allowing any origin to access the resource.
For example, to allow http://mozilla.org to access the resource, you can specify:
Access-Control-Allow-Origin: http://mozilla.org
If the server specifies an origin host rather than "*", then it could also include Origin in the Vary response header to indicate to clients that server responses will differ based on the value of the Origin request header.
The {{HTTPHeader("Access-Control-Expose-Headers")}} header lets a server whitelist headers that browsers are allowed to access. For example:
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
This allows the X-My-Custom-Header
and X-Another-Custom-Header
headers to be exposed to the browser.
The {{HTTPHeader("Access-Control-Max-Age")}} header indicates how long the results of a preflight request can be cached. For an example of a preflight request, see the above examples.
Access-Control-Max-Age: <delta-seconds>
The delta-seconds
parameter indicates the number of seconds the results can be cached.
The {{HTTPHeader("Access-Control-Allow-Credentials")}} header Indicates whether or not the response to the request can be exposed when the credentials
flag is true. When used as part of a response to a preflight request, this indicates whether or not the actual request can be made using credentials. Note that simple GET
requests are not preflighted, and so if a request is made for a resource with credentials, if this header is not returned with the resource, the response is ignored by the browser and not returned to web content.
Access-Control-Allow-Credentials: true
Credentialed requests are discussed above.
The {{HTTPHeader("Access-Control-Allow-Methods")}} header specifies the method or methods allowed when accessing the resource. This is used in response to a preflight request. The conditions under which a request is preflighted are discussed above.
Access-Control-Allow-Methods: <method>[, <method>]*
An example of a preflight request is given above, including an example which sends this header to the browser.
The {{HTTPHeader("Access-Control-Allow-Headers")}} header is used in response to a preflight request to indicate which HTTP headers can be used when making the actual request.
Access-Control-Allow-Headers: <field-name>[, <field-name>]*
This section lists headers that clients may use when issuing HTTP requests in order to make use of the cross-origin sharing feature. Note that these headers are set for you when making invocations to servers. Developers using cross-site {{domxref("XMLHttpRequest")}} capability do not have to set any cross-origin sharing request headers programmatically.
The {{HTTPHeader("Origin")}} header indicates the origin of the cross-site access request or preflight request.
Origin: <origin>
The origin is a URI indicating the server from which the request initiated. It does not include any path information, but only the server name.
origin
can be the empty string; this is useful, for example, if the source is a data
URL.Note that in any access control request, the {{HTTPHeader("Origin")}} header is always sent.
The {{HTTPHeader("Access-Control-Request-Method")}} is used when issuing a preflight request to let the server know what HTTP method will be used when the actual request is made.
Access-Control-Request-Method: <method>
Examples of this usage can be found above.
The {{HTTPHeader("Access-Control-Request-Headers")}} header is used when issuing a preflight request to let the server know what HTTP headers will be used when the actual request is made.
Access-Control-Request-Headers: <field-name>[, <field-name>]*
Examples of this usage can be found above.
Specification | Status | Comment |
---|---|---|
{{SpecName('Fetch', '#cors-protocol', 'CORS')}} | {{Spec2('Fetch')}} | New definition; supplants W3C CORS specification. |
The compatibility table in this page is generated from structured data. If you'd like to contribute to the data, please check out https://github.com/mdn/browser-compat-data and send us a pull request.
{{Compat("http.headers.Access-Control-Allow-Origin")}}
XDomainRequest
object, but have a full implementation in IE 10.drawImage
.XMLHttpRequest
and Cross-Origin Resource Sharing