Movatterモバイル変換


[0]ホーム

URL:


  1. Веб-технологии для разработчиков
  2. HTTP
  3. Guides
  4. Cross-Origin Resource Sharing (CORS)

This page was translated from English by the community.Learn more and join the MDN Web Docs community.

View in EnglishAlways switch to English

Cross-Origin Resource Sharing (CORS)

Baseline Widely available

This feature is well established and works across many devices and browser versions. It’s been available across browsers since ⁨июль 2015 г.⁩.

Cross-Origin Resource Sharing (CORS) — механизм, использующий дополнительныеHTTP-заголовки, чтобы дать возможностьагенту пользователя получать разрешения на доступ к выбранным ресурсам с сервера на источнике (домене), отличном от того, что сайт использует в данный момент. Говорят, что агент пользователя делает запрос с другого источника(cross-origin HTTP request), если источник текущего документа отличается от запрашиваемого ресурса доменом, протоколом или портом.

Пример cross-origin запроса: HTML страница, обслуживаемая сервером сhttp://domain-a.com, запрашивает<img> src по адресуhttp://domain-b.com/image.jpg. Сегодня многие страницы загружают ресурсы вроде CSS-стилей, изображений и скриптов с разных доменов, соответствующих разным сетям доставки контента (Content delivery networks, CDNs).

В целях безопасности браузеры ограничивают cross-origin запросы, инициируемые скриптами. Например,XMLHttpRequest иFetch API следуютполитике одного источника (same-origin policy). Это значит, что web-приложения, использующие такие API, могут запрашивать HTTP-ресурсы только с того домена, с которого были загружены, пока не будут использованы CORS-заголовки.

Механизм CORS поддерживает кросс-доменные запросы и передачу данных между браузером и web-серверами по защищённому соединению. Современные браузеры используют CORS в API-контейнерах, таких какXMLHttpRequest илиFetch, чтобы снизить риски, присущие запросам с других источников.

Кто должен читать данную статью?

На самом деле, все.

Конкретнее, эта статья для web-администраторов, разработчиков серверной стороны и front-end разработчиков. Современные браузеры поддерживают клиентские компоненты cross-origin обмена, включая заголовки и соблюдение правил политики. Но этот новый стандарт означает, что сервера также должны поддерживать новые заголовки запросов и ответов. Другая статья для разработчиков серверной части, описывающаяперспективы cross-origin обмена на стороне сервера (с примерами кода на PHP), к дополнительному прочтению.

Какие запросы используют CORS?

Этотстандарт cross-origin обмена используется для разрешения кросс-сайтовых HTTP запросов для:

Эта статья описывает общие понятия Cross-Origin Resource Sharing и включает обсуждение необходимых HTTP заголовков.

Обзор функциональности

Стандарт Cross-Origin Resource Sharing работает с помощью добавления новыхHTTP-заголовков, которые позволяют серверам описывать набор источников, которым разрешено читать информацию, запрашиваемую web-браузером. В частности, для методов HTTP-запросов, которые могут привести к побочным эффектам над данными сервера (в частности, для HTTP методов, отличных отGET или дляPOST запросов, использующих определённыеMIME-типы), спецификация требует, чтобы браузеры "предпроверяли" запрос, запрашивая поддерживающие методы с сервера с помощью метода HTTP-запросаOPTIONS и затем, поверх "подтверждения" с сервера, отсылали фактический запрос с фактическим методом HTTP-запроса. Сервера также могут оповещать клиентов должны ли "полномочия" (включаяCookies и HTTP Authentication данные) быть отправлены с запросом.

Следующая секция описывает сценарии, а также предоставляет анализ использования HTTP-заголовков.

Примеры сценариев управления доступом

Здесь мы рассмотрим три сценария, которые иллюстрируют как Cross-Origin Resource Sharing работает. Каждый сценарий использует объектXMLHttpRequest, который может быть использован для межсайтового взаимодействия, в любом, поддерживающем данный объект, браузере.

Фрагменты JavaScript-кода, включённые в эти секции (а также фрагменты кода, отвечающие за корректную обработку межсерверных запросов, которые запускаются на сервере) могут быть испытаны "в действии" наhttp://arunranga.com/examples/access-control/, и будут работать в браузерах, которые поддерживаютXMLHttpRequest.

Обсуждение Cross-Origin Resource Sharing с точки зрения сервера (включая фрагменты кода на PHP) может быть найдено в статьеServer-Side Access Control (CORS).

Простые запросы

Некоторые запросы не заставляют срабатыватьCORS preflight. Они называютсяпростыми запросами согласно устаревшейспецификации CORS (англ.), тогда какспецификация Fetch, которая в настоящее время определяет CORS, не использует данный термин.

«Простой запрос» — это запрос, удовлетворяющий следующим условиям:

Примечание:These are the same kinds of cross-site requests that web content can already issue, and no response data is released to the requester unless the server sends an appropriate header. Therefore, sites that prevent cross-site request forgery have nothing new to fear from HTTP access control.

Примечание:WebKit Nightly и Safari Technology Preview устанавливают дополнительные ограничения на значения, допустимые в заголовкахAccept,Accept-Language, иContent-Language. Если любой из этих заголовков имеет "нестандартное" значение, WebKit/Safari используют предварительный запрос. Значения, которые WebKit/Safari считают "нестандартными" для этих заголовков, перечислены только в следующих проблемах WebKit:Require preflight for non-standard CORS-safelisted request headers Accept, Accept-Language, and Content-Language,Allow commas in Accept, Accept-Language, and Content-Language request headers for simple CORS, иSwitch to a blacklist model for restricted Accept headers in simple CORS requests. Во всех других браузерах подобных дополнительных ограничений нет, потому что они не являются частью спецификации.

Например, представьте, что содержимое доменаhttp://foo.example хочет обратиться к содержимомуhttp://bar.other. На доменеhttp://foo.example может использоваться следующий Javascript код:

js
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.1Host: bar.otherUser-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3preAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: en-us,en;q=0.5Accept-Encoding: gzip,deflateConnection: keep-aliveReferer: http://foo.example/examples/access-control/simpleXSInvocation.htmlOrigin: http://foo.exampleHTTP/1.1 200 OKDate: Mon, 01 Dec 2008 00:23:53 GMTServer: Apache/2.0.61Access-Control-Allow-Origin: *Keep-Alive: timeout=2, max=100Connection: Keep-AliveTransfer-Encoding: chunkedContent-Type: application/xml[XML Data]

Строчки 1 - 10 это заголовки отправленного запроса. Самым интересующим здесь для нас заголовком являетсяOrigin, указанный на 10 строке. Данный заголовок указывает, что запрос пришёл из содержимого доменаhttp://foo.example.

Строчки 13 - 22 показывают HTTP-ответ от сервера на доменhttp://bar.other. В ответ сервер возвращаетAccess-Control-Allow-Origin заголовок, указанный на 16 строке. Использование заголовковOrigin header иAccess-Control-Allow-Origin показывает протокол контроля доступа в простейшем виде. В этом случае, сервер отвечает сAccess-Control-Allow-Origin: * что означает, что к ресурсу может получить доступ слюбого домена кросс-сайтовым способом. Владелец ресурсаhttp://bar.other может ограничить доступ к ресурсу для запросов только сhttp://foo.example, указав:

Access-Control-Allow-Origin: http://foo.example

Отметьте, никакой домен, кромеhttp://foo.example (определён ORIGIN: заголовок в запросе, как в 10 строке выше), не может получить доступ к ресурсу кросс-сайтовым способом. ЗаголовокAccess-Control-Allow-Origin должен содержать значение, которое было отправлено в заголовкеOrigin запроса.

Предварительные запросы

В отличии от"простых запросов", "предварительные" запросы сначала отправляют HTTP-запрос методомOPTIONS к ресурсу на другом домене, чтобы определить, является ли фактический запрос безопасным для отправки. Кросс-сайтовые запросы предварительно просматриваются таким образом, так как они могут быть причастны к пользовательским данным.

В частности, запрос предварительно просматривается, если выполняетсялюбое из следующих условий:

Ниже приведён пример запроса, который будет предварительно просмотрен.

js
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);    }}......

В примере выше, 3 строка создаёт XML тело, чтобы отправитьPOST запросом на строке 8. Также, на строке 9, "кастомизированный" (не стандартный) заголовок HTTP запроса установлен (X-PINGOTHER: pingpong). Такие заголовки не являются частью протокола HTTP/1.1, но, как правило, полезны для веб-приложений. Так как запрос использует Content-Typeapplication/xml, и так как установлен кастомизированный заголовок, этот запрос просматривается.

Примечание:Как описано ниже, фактическийPOST запрос не включаетAccess-Control-Request-* заголовки; они нужны только дляOPTIONS запроса.

Давайте посмотрим на полный обмен между клиентом и сервером. Первый обмен - этопредварительныйзапрос/ответ:

OPTIONS /resources/post-here/ HTTP/1.1Host: bar.otherUser-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3preAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: en-us,en;q=0.5Accept-Encoding: gzip,deflateConnection: keep-aliveOrigin: http://foo.exampleAccess-Control-Request-Method: POSTAccess-Control-Request-Headers: X-PINGOTHER, Content-TypeHTTP/1.1 200 OKDate: Mon, 01 Dec 2008 01:15:39 GMTServer: Apache/2.0.61 (Unix)Access-Control-Allow-Origin: http://foo.exampleAccess-Control-Allow-Methods: POST, GET, OPTIONSAccess-Control-Allow-Headers: X-PINGOTHER, Content-TypeAccess-Control-Max-Age: 86400Vary: Accept-Encoding, OriginContent-Encoding: gzipContent-Length: 0Keep-Alive: timeout=2, max=100Connection: Keep-AliveContent-Type: text/plain

Как только предварительный запрос завершён, отправляется настоящий запрос:

POST /resources/post-here/ HTTP/1.1Host: bar.otherUser-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3preAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: en-us,en;q=0.5Accept-Encoding: gzip,deflateConnection: keep-aliveX-PINGOTHER: pingpongContent-Type: text/xml; charset=UTF-8Referer: http://foo.example/examples/preflightInvocation.htmlContent-Length: 55Origin: http://foo.examplePragma: no-cacheCache-Control: no-cache<?xml version="1.0"?><person><name>Arun</name></person>HTTP/1.1 200 OKDate: Mon, 01 Dec 2008 01:15:40 GMTServer: Apache/2.0.61 (Unix)Access-Control-Allow-Origin: http://foo.exampleVary: Accept-Encoding, OriginContent-Encoding: gzipContent-Length: 235Keep-Alive: timeout=2, max=99Connection: Keep-AliveContent-Type: text/plain[Some GZIP'd payload]

Строки 1 - 12 выше представляют предварительный запрос сOPTIONS методом. Браузер определяет, что ему нужно отправить это, основываясь на параметрах запроса, которые использовались во фрагменте кода JavaScript выше, чтобы сервер мог ответить, допустимо ли отправить запрос с фактическими параметрами запроса. OPTIONS - это метод HTTP/1.1, который используется для определения дополнительной информации от серверов, и являетсяsafe методом, что означает, что его нельзя использовать для изменения ресурса. Обратите внимание, что вместе с запросом OPTIONS отправляются два других заголовка запроса (строки 10 и 11 соответственно):

Access-Control-Request-Method: POSTAccess-Control-Request-Headers: X-PINGOTHER, Content-Type

ЗаголовокAccess-Control-Request-Method уведомляет сервер как часть предварительного запроса о том, что при отправке фактического запроса он будет отправлен методом запросаPOST. ЗаголовокAccess-Control-Request-Headers уведомляет сервер о том, что при отправке фактического запроса он будет отправлен с пользовательскими заголовкамиX-PINGOTHER и Content-Type. Теперь у сервера есть возможность определить, хочет ли он принять запрос в этих обстоятельствах.

Строки 14 - 26 выше - это ответ, который сервер отправляет обратно, указывая, что метод запроса (POST) и заголовки запроса (X-PINGOTHER) являются приемлемыми. В частности, давайте посмотрим на строки 17-20:

Access-Control-Allow-Origin: http://foo.exampleAccess-Control-Allow-Methods: POST, GET, OPTIONSAccess-Control-Allow-Headers: X-PINGOTHER, Content-TypeAccess-Control-Max-Age: 86400

Сервер отвечает сAccess-Control-Allow-Methods и сообщает, чтоPOST,GET, иOPTIONS являются жизнеспособными методами для запроса соответствующего ресурса. Обратите внимание, что этот заголовок похож на заголовок ответаAllow, но используется строго в контексте контроля доступа.

Сервер также отправляетAccess-Control-Allow-Headers со значением "X-PINGOTHER, Content-Type", подтверждая, что это разрешённые заголовки, которые будут использоваться с фактическим запросом. Как иAccess-Control-Allow-Methods,Access-Control-Allow-Headers представляет собой список допустимых заголовков через запятую.

Наконец,Access-Control-Max-Age даёт значение в секундах, в течение которого можно кешировать ответ на предварительный запрос без отправки другого предварительного запроса. В этом случае, 86400 секунды - это 24 часа. Обратите внимание, что каждый браузер имеетмаксимальное внутреннее значение, которое имеет приоритет, когдаAccess-Control-Max-Age больше.

Предварительные запросы и переадресации

Большинство браузеров в настоящее время не поддерживают следующие переадресации для предварительных запросов. Если переадресация происходит для предварительного запроса, большинство современных браузеров сообщат об ошибке, такой как следующее.

Запрос был перенаправлен на 'https://example.com/foo', который запрещён для запросов из разных источников, требующих предварительной проверки

Запрос требует предварительной проверки, которая запрещена для перенаправления между источниками

Протокол CORS изначально требовал такого поведения, но впоследствиибыл изменён, чтобы больше не требовать его. Однако большинство браузеров ещё не реализовали это изменение и все ещё демонстрируют поведение, которое требовалось изначально.

Поэтому, пока браузеры не догонят спецификацию, вы можете обойти это ограничение, выполнив одно или оба из следующих действий:

  • изменить поведение на стороне сервера, чтобы избежать предварительной проверки и/или избежать переадресации — если у вас есть контроль над сервером, к которому делается запрос
  • изменить запрос так, чтобы это былпростой запрос, который не вызывает предварительную проверку

Но если невозможно внести эти изменения, то возможен другой способ:

  1. Сделайтепростой запрос для определения (используяResponse.url для Fetch API, илиXHR.responseURL, чтобы определить, на каком URL завершится настоящий предварительный запрос).
  2. Сделайте другой запрос ("настоящий" запрос), используя URL адрес, полученный вами изResponse.url илиXMLHttpRequest.responseURL на первом этапе.

Однако, если запрос инициирует предварительную проверку из-за наличия в запросе заголовкаAuthorization, вы не сможете обойти ограничение, используя описанные выше шаги. И вы вообще не сможете обойти это, если у вас нет контроля над сервером, на который делается запрос.

Запросы с учётными данными

Наиболее интересная возможность, предоставляемая какXMLHttpRequest, так иFetch и CORS - это возможность делать "проверенные" запросы, которые осведомлены о файлахHTTP cookie и информации HTTP аутентификации. По умолчанию, в кросс-сайтовыхXMLHttpRequest илиFetch вызовах, браузерыне отправляют учётные данные. Конкретный флаг должен быть установлен для объектаXMLHttpRequest или конструктораRequest при его вызове.

В этом примере контент, изначально загруженный изhttp://foo.example, выполняет простой GET запрос к ресурсуhttp://bar.other, который устанавливает файлы cookie. Содержимое на foo.example может содержать такой #"http://bar.other/resources/credentialed-content/";function callOtherDomain() { if (invocation) { invocation.open("GET", url, true); invocation.withCredentials = true; invocation.onreadystatechange = handler; invocation.send(); }}

В строке 7 показан флагXMLHttpRequest, который должен быть установлен для выполнения вызова с помощью файлов cookie, а именно логическое значениеwithCredentials. По умолчанию вызов выполняется без файлов cookie. Поскольку это простой запросGET, он не является предварительным, но браузеротклоняет любой ответ, который не имеет заголовкаAccess-Control-Allow-Credentials: true, ине создаёт ответ, доступный для вызова веб-контента.

Вот пример обмена между клиентом и сервером:

GET /resources/access-control-with-credentials/ HTTP/1.1Host: bar.otherUser-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3preAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: en-us,en;q=0.5Accept-Encoding: gzip,deflateConnection: keep-aliveReferer: http://foo.example/examples/credential.htmlOrigin: http://foo.exampleCookie: pageAccess=2HTTP/1.1 200 OKDate: Mon, 01 Dec 2008 01:34:52 GMTServer: 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.2X-Powered-By: PHP/5.2.6Access-Control-Allow-Origin: http://foo.exampleAccess-Control-Allow-Credentials: trueCache-Control: no-cachePragma: no-cacheSet-Cookie: pageAccess=3; expires=Wed, 31-Dec-2008 01:34:53 GMTVary: Accept-Encoding, OriginContent-Encoding: gzipContent-Length: 106Keep-Alive: timeout=2, max=100Connection: Keep-AliveContent-Type: text/plain[text/plain payload]

Также в строке 11 содержится Cookie, предназначенный для контента ресурсаhttp://bar.other. В случае еслиhttp://bar.other не ответит полемAccess-Control-Allow-Credentials: true (строка 19), то ответ от сервера будет проигнорирован и не станет доступным для веб-контента.

Запросы с учётными данными и wildcards

В процессе ответа на запрос с учётными данными серверобязан указать точный источник в поле заголовкаAccess-Control-Allow-Origin вместо спецсимвола "*".

Из-за того что заголовки запроса в примере выше включают заголовокCookie, запрос провалился бы, если бы значение заголовкаControl-Allow-Origin было "*". Но он не провалился: потому что значение заголовкаAccess-Control-Allow-Origin - "http://foo.example" (действительный источник), а не спецсимвол "*", контент, удостоверяющий полномочия, возвращается в вызывающий веб-контент.

Отметьте, что заголовок ответаSet-Cookie в примере выше также устанавливает дополнительные куки. В случае неудачи, возникает исключение, в зависимости от используемого API.

Заголовки HTTP ответов

Эта секция содержит список заголовков HTTP ответов, которые сервер шлёт в ответ на запрос доступа, как описано в спецификации совместного использования ресурсов между разными источниками. В предыдущей секции это описано в действии.

Access-Control-Allow-Origin

Возвращаемый ресурс может иметь один заголовокAccess-Control-Allow-Origin, синтаксис которого:

Access-Control-Allow-Origin: <origin> | *

Access-Control-Allow-Origin определяет либо один источник, что указывает браузеру разрешить этому источнику доступ к ресурсу; либо — для запросов без учётных данных — значение "*", которое говорит браузеру разрешить запросы из любых источников.

Например, чтобы разрешитьhttp://mozilla.org доступ к ресурсу, можно указать:

Access-Control-Allow-Origin: http://mozilla.org

Если сервер возвращает название хоста, вместо "*", также может быть указан заголовок Vary со значением Origin, чтобы показать клиентам, что ответы с сервера будут отличаться в зависимости от значения заголовка запроса Origin.

Access-Control-Expose-Headers

TheAccess-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 theX-My-Custom-Header andX-Another-Custom-Header headers to be exposed to the browser.

Access-Control-Max-Age

TheAccess-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>

Thedelta-seconds parameter indicates the number of seconds the results can be cached.

Access-Control-Allow-Credentials

TheAccess-Control-Allow-Credentials header Indicates whether or not the response to the request can be exposed when thecredentials 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 simpleGET 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.

Access-Control-Allow-Methods

TheAccess-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 apreflight request is given above, including an example which sends this header to the browser.

Access-Control-Allow-Headers

TheAccess-Control-Allow-Headers header is used in response to apreflight request to indicate which HTTP headers can be used when making the actual request.

Access-Control-Allow-Headers: <field-name>[, <field-name>]*

The HTTP request headers

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-siteXMLHttpRequest capability do not have to set any cross-origin sharing request headers programmatically.

Origin

TheOrigin 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.

Примечание:Theorigin can be the empty string; this is useful, for example, if the source is adata URL.

Note that in any access control request, theOrigin header isalways sent.

Access-Control-Request-Method

TheAccess-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 befound above.

Access-Control-Request-Headers

TheAccess-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 befound above.

Спецификации

Specification
Fetch
# http-access-control-allow-origin

Совместимость с браузерами

Compatibility notes

  • Internet Explorer 8 and 9 expose CORS via theXDomainRequest object, but have a full implementation in IE 10.
  • While Firefox 3.5 introduced support for cross-site XMLHttpRequests and Web Fonts, certain requests were limited until later versions. Specifically, Firefox 7 introduced the ability for cross-site HTTP requests for WebGL Textures, and Firefox 9 added support for Images drawn on a canvas usingdrawImage.

Смотрите также

Help improve MDN

Learn how to contribute

This page was last modified on byMDN contributors.


[8]ページ先頭

©2009-2025 Movatter.jp