Cross-Origin Resource Sharing (CORS)
Cross-Origin Resource Sharing (CORS) — механизм, использующий дополнительные HTTP-заголовки, чтобы дать возможность агенту пользователя получать разрешения на доступ к выбранным ресурсам с сервера на источнике (домене), отличном от того, что сайт использует в данный момент. Говорят, что агент пользователя делает запрос с другого источника (cross-origin HTTP request), если источник текущего документа отличается от запрашиваемого ресурса доменом, протоколом или портом.
Пример cross-origin запроса: HTML страница, обслуживаемая сервером с http://domain-a.com , запрашивает 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) (en-US) , к дополнительному прочтению.
Какие запросы используют CORS?
Этот стандарт cross-origin обмена используется для разрешения кросс-сайтовых HTTP запросов для:
- Вызова XMLHttpRequest или Fetch APIs в кросс-сайт манере, как описано выше.
- Web Fonts (для кросс-доменного использования шрифтов в @font-face в рамках CSS), чтобы серверы могли разворачивать TrueType шрифты, которые могут быть загружены только кросс-сайт и использованы web-сайтами, которым это разрешено.
- WebGL текстуры.
- Фреймы с изображениями/видео, добавленными в канвас с помощью drawImage .
- Стили (для CSSOM (en-US) доступа).
- Скрипты (для отключённых исключений).
Эта статья описывает общие понятия 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) (en-US) .
Простые запросы
Некоторые запросы не заставляют срабатывать CORS preflight (en-US). Они называются простыми запросами согласно устаревшей спецификации CORS (англ.), тогда как спецификация Fetch, которая в настоящее время определяет CORS, не использует данный термин.
«Простой запрос» — это запрос, удовлетворяющий следующим условиям:
- Допустимые методы для запроса:
- GET
- HEAD
- POST
- Accept
- Accept-Language
- Content-Language
- Content-Type (но учитывайте примечание ниже)
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
Примечание: 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 код:
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; 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]
Строчки 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 , указав:
Отметьте, никакой домен, кроме http://foo.example (определён ORIGIN: заголовок в запросе, как в 10 строке выше), не может получить доступ к ресурсу кросс-сайтовым способом. Заголовок Access-Control-Allow-Origin должен содержать значение, которое было отправлено в заголовке Origin запроса.
Предварительные запросы
В отличии от «простых запросов» (en-US) , «предварительные» запросы сначала отправляют HTTP-запрос методом OPTIONS к ресурсу на другом домене, чтобы определить, является ли фактический запрос безопасным для отправки. Кросс-сайтовые запросы предварительно просматриваются таким образом, так как они могут быть причастны к пользовательским данным.
В частности, запрос предварительно просматривается, если выполняется любое из следующих условий:
- Если в запросе используется любой из следующих методов:
- PUT
- DELETE
- CONNECT
- OPTIONS
- TRACE
- PATCH
- Accept
- Accept-Language
- Content-Language
- Content-Type (но учтите дополнительные требования ниже)
- Last-Event-ID
- DPR
- Save-Data
- Viewport-Width
- Width
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
Ниже приведён пример запроса, который будет предварительно просмотрен.
var invocation = new XMLHttpRequest(); var url = 'http://bar.other/resources/post-here/'; var body = '
'; 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); > > . .Arun В примере выше, 3 строка создаёт XML тело, чтобы отправить POST запросом на строке 8. Также, на строке 9, «кастомизированный» (не стандартный) заголовок HTTP запроса установлен ( X-PINGOTHER: pingpong ). Такие заголовки не являются частью протокола HTTP/1.1, но, как правило, полезны для веб-приложений. Так как запрос использует Content-Type application/xml , и так как установлен кастомизированный заголовок, этот запрос просматривается.

Примечание: как описано ниже, фактический POST запрос не включает Access-Control-Request-* заголовки; они нужны только для OPTIONS запроса.
Давайте посмотрим на полный обмен между клиентом и сервером. Первый обмен — это предварительный запрос/ответ:
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, OPTIONS 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
Как только предварительный запрос завершён, отправляется настоящий запрос:
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
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]Arun Строки 1 — 12 выше представляют предварительный запрос с OPTIONS методом. Браузер определяет, что ему нужно отправить это, основываясь на параметрах запроса, которые использовались во фрагменте кода JavaScript выше, чтобы сервер мог ответить, допустимо ли отправить запрос с фактическими параметрами запроса. OPTIONS — это метод HTTP/1.1, который используется для определения дополнительной информации от серверов, и является safe методом, что означает, что его нельзя использовать для изменения ресурса. Обратите внимание, что вместе с запросом OPTIONS отправляются два других заголовка запроса (строки 10 и 11 соответственно):
Access-Control-Request-Method: POST Access-Control-Request-Headers: X-PINGOTHER, Content-Type
Заголовок Access-Control-Request-Method (en-US) уведомляет сервер как часть предварительного запроса о том, что при отправке фактического запроса он будет отправлен методом запроса POST . Заголовок Access-Control-Request-Headers (en-US) уведомляет сервер о том, что при отправке фактического запроса он будет отправлен с пользовательскими заголовками X-PINGOTHER и Content-Type. Теперь у сервера есть возможность определить, хочет ли он принять запрос в этих обстоятельствах.
Строки 14 — 26 выше — это ответ, который сервер отправляет обратно, указывая, что метод запроса ( POST ) и заголовки запроса ( X-PINGOTHER ) являются приемлемыми. В частности, давайте посмотрим на строки 17-20:
Access-Control-Allow-Origin: http://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-Methods и сообщает, что POST , GET , и OPTIONS являются жизнеспособными методами для запроса соответствующего ресурса. Обратите внимание, что этот заголовок похож на заголовок ответа Allow (en-US) , но используется строго в контексте контроля доступа.
Сервер также отправляет 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 изначально требовал такого поведения, но впоследствии был изменён, чтобы больше не требовать его. Однако большинство браузеров ещё не реализовали это изменение и все ещё демонстрируют поведение, которое требовалось изначально.
Поэтому, пока браузеры не догонят спецификацию, вы можете обойти это ограничение, выполнив одно или оба из следующих действий:
- изменить поведение на стороне сервера, чтобы избежать предварительной проверки и/или избежать переадресации — если у вас есть контроль над сервером, к которому делается запрос
- изменить запрос так, чтобы это был простой запрос, который не вызывает предварительную проверку
Но если невозможно внести эти изменения, то возможен другой способ:
- Сделайте простой запрос (en-US) для определения (используя Response.url (en-US) для Fetch API, или XHR.responseURL, чтобы определить, на каком URL завершится настоящий предварительный запрос).
- Сделайте другой запрос («настоящий» запрос), используя URL адрес, полученный вами из Response.url (en-US) или XMLHttpRequest.responseURL на первом этапе.
Однако, если запрос инициирует предварительную проверку из-за наличия в запросе заголовка Authorization , вы не сможете обойти ограничение, используя описанные выше шаги. И вы вообще не сможете обойти это, если у вас нет контроля над сервером, на который делается запрос.
Запросы с учётными данными
Наиболее интересная возможность, предоставляемая как XMLHttpRequest , так и Fetch и CORS — это возможность делать «проверенные» запросы, которые осведомлены о файлах HTTP cookie и информации HTTP аутентификации. По умолчанию, в кросс-сайтовых XMLHttpRequest или Fetch вызовах, браузеры не отправляют учётные данные. Конкретный флаг должен быть установлен для объекта XMLHttpRequest или конструктора Request при его вызове.
В этом примере контент, изначально загруженный из http://foo.example, выполняет простой GET запрос к ресурсу http://bar.other, который устанавливает файлы cookie. Содержимое на foo.example может содержать такой JavaScript:
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(); > >
В строке 7 показан флаг XMLHttpRequest , который должен быть установлен для выполнения вызова с помощью файлов cookie, а именно логическое значение withCredentials . По умолчанию вызов выполняется без файлов cookie. Поскольку это простой запрос GET, он не является предварительным, но браузер отклоняет любой ответ, который не имеет заголовка Access-Control-Allow-Credentials (en-US) : true , и не создаёт ответ, доступный для вызова веб-контента.

Вот пример обмена между клиентом и сервером:
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]
Также в строке 11 содержится Cookie, предназначенный для контента ресурса http://bar.other . В случае если http://bar.other не ответит полем Access-Control-Allow-Credentials (en-US) : 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: | *
Access-Control-Allow-Origin определяет либо один источник, что указывает браузеру разрешить этому источнику доступ к ресурсу; либо — для запросов без учётных данных — значение » * «, которое говорит браузеру разрешить запросы из любых источников.
Например, чтобы разрешить http://mozilla.org доступ к ресурсу, можно указать:
Access-Control-Allow-Origin: http://mozilla.org
Если сервер возвращает название хоста, вместо «*», также может быть указан заголовок Vary со значением Origin, чтобы показать клиентам, что ответы с сервера будут отличаться в зависимости от значения заголовка запроса Origin.
Access-Control-Expose-Headers
The Access-Control-Expose-Headers (en-US) 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.
Access-Control-Max-Age
The 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:
The delta-seconds parameter indicates the number of seconds the results can be cached.
Access-Control-Allow-Credentials
The Access-Control-Allow-Credentials (en-US) 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
Access-Control-Allow-Methods
The 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: [, ]*
An example of a preflight request is given above, including an example which sends this header to the browser.
Access-Control-Allow-Headers
The 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: [, ]*
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-site XMLHttpRequest capability do not have to set any cross-origin sharing request headers programmatically.
Origin
The Origin header indicates the origin of the cross-site access request or preflight request.
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.
Примечание: The 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 Origin header is always sent.
Access-Control-Request-Method
The Access-Control-Request-Method (en-US) 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:
Examples of this usage can be found above.
Access-Control-Request-Headers
The Access-Control-Request-Headers (en-US) 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: [, ]*
Examples of this usage can be found above.
Specifications
Specification Fetch Standard
# http-access-control-allow-originBrowser compatibility
BCD tables only load in the browser
Compatibility notes
- Internet Explorer 8 and 9 expose CORS via the XDomainRequest 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 using drawImage .
See also
- Code Samples Showing XMLHttpRequest and Cross-Origin Resource Sharing
- Cross-Origin Resource Sharing From a Server-Side Perspective (PHP, etc.) (en-US)
- Cross-Origin Resource Sharing specification
- XMLHttpRequest
- Fetch API
- Using CORS with All (Modern) Browsers
- Using CORS — HTML5 Rocks
- Stack Overflow answer with «how to» info for dealing with common problems:
- How to avoid the CORS preflight
- How to use a CORS proxy to get around «No Access-Control-Allow-Origin header»
- How to fix «Access-Control-Allow-Origin header must not be the wildcard»
Found a content problem with this page?
- Edit the page on GitHub.
- Report the content issue.
- View the source on GitHub.
This page was last modified on 11 окт. 2023 г. by MDN contributors.
Your blueprint for a better internet.
Fetch API
Давайте рассмотрим оставшуюся часть API, чтобы охватить все возможности.
На заметку:
Заметим: большинство этих возможностей используются редко. Вы можете пропустить эту главу и, несмотря на это, нормально использовать fetch .
Тем не менее, полезно знать, что вообще может fetch , чтобы, когда появится необходимость, вернуться и прочитать конкретные детали.
Нижеследующий список – это все возможные опции для fetch с соответствующими значениями по умолчанию (в комментариях указаны альтернативные значения):
let promise = fetch(url, < method: "GET", // POST, PUT, DELETE, etc. headers: < // значение этого заголовка обычно ставится автоматически, // в зависимости от тела запроса "Content-Type": "text/plain;charset=UTF-8" >, body: undefined, // string, FormData, Blob, BufferSource или URLSearchParams referrer: "about:client", // или "" для того, чтобы не послать заголовок Referer, // или URL с текущего источника referrerPolicy: "strict-origin-when-cross-origin", // no-referrer-when-downgrade, no-referrer, origin, same-origin. mode: "cors", // same-origin, no-cors credentials: "same-origin", // omit, include cache: "default", // no-store, reload, no-cache, force-cache или only-if-cached redirect: "follow", // manual, error integrity: "", // контрольная сумма, например "sha256-abcdef1234567890" keepalive: false, // true signal: undefined, // AbortController, чтобы прервать запрос window: window // null >);Довольно-таки внушительный список, не так ли?
В главе Fetch мы разобрали параметры method , headers и body .
Опция signal разъяснена в главе в Fetch: прерывание запроса.
Теперь давайте пройдёмся по оставшимся возможностям.
referrer, referrerPolicy
Данные опции определяют, как fetch устанавливает HTTP-заголовок Referer .
Обычно этот заголовок ставится автоматически и содержит URL-адрес страницы, с которой пришёл запрос. В большинстве случаев он совсем неважен, в некоторых случаях, с целью большей безопасности, имеет смысл убрать или укоротить его.
Опция referrer позволяет установить любой Referer в пределах текущего источника или же убрать его.
Чтобы не отправлять Referer , нужно указать значением пустую строку:
fetch('/page', < referrer: "" // не ставить заголовок Referer >);Для того, чтобы установить другой URL-адрес (должен быть с текущего источника):
fetch('/page', < // предположим, что мы находимся на странице https://javascript.info // мы можем установить любое значение Referer при условии, что оно принадлежит текущему источнику referrer: "https://javascript.info/anotherpage" >);Опция referrerPolicy устанавливает общие правила для Referer .
Выделяется 3 типа запросов:
- Запрос на тот же источник.
- Запрос на другой источник.
- Запрос с HTTPS to HTTP (с безопасного протокола на небезопасный).
В отличие от настройки referrer , которая позволяет задать точное значение Referer , настройка referrerPolicy сообщает браузеру общие правила, что делать для каждого типа запроса.
- «strict-origin-when-cross-origin» – значение по умолчанию: для «same-origin» отправлять полный Referer , для «cross-origin» отправлять только «origin» , если только это не HTTPS→HTTP запрос, тогда не отправлять ничего.
- «no-referrer-when-downgrade» – всегда отправлять полный Referer , за исключением случаев, когда мы отправляем запрос с HTTPS на HTTP (на менее безопасный протокол).
- «no-referrer» – никогда не отправлять Referer .
- «origin» – отправлять в Referer только текущий источник, а не полный URL-адрес страницы, например, посылать только http://site.com вместо http://site.com/path .
- «origin-when-cross-origin» – отправлять полный Referer для запросов в пределах текущего источника, но для запросов на другой источник отправлять только сам источник (как выше).
- «same-origin» – отправлять полный Referer для запросов в пределах текущего источника, а для запросов на другой источник не отправлять его вообще.
- «strict-origin» – отправлять только значение источника, не отправлять Referer для HTTPS→HTTP запросов.
- «unsafe-url» – всегда отправлять полный URL-адрес в Referer , даже при запросах HTTPS→HTTP .
Вот таблица со всеми комбинациями:
Значение На тот же источник На другой источник HTTPS→HTTP «no-referrer» — — — «no-referrer-when-downgrade» full full — «origin» origin origin origin «origin-when-cross-origin» full origin origin «same-origin» full — — «strict-origin» origin origin — «strict-origin-when-cross-origin» или «» (по умолчанию) full origin — «unsafe-url» full full full Допустим, у нас есть админка со структурой URL, которая не должна стать известной снаружи сайта.
Если мы отправляем запрос fetch , то по умолчанию он всегда отправляет заголовок Referer с полным URL-адресом нашей админки (исключение – это когда мы делаем запрос от HTTPS в HTTP, в таком случае Referer не будет отправляться).
Например, Referer: https://javascript.info/admin/secret/paths .
Если мы хотим, чтобы другие сайты получали только источник, но не URL-путь, это сделает такая настройка:
fetch('https://another.com/page', < // . referrerPolicy: "origin-when-cross-origin" // Referer: https://javascript.info >);Мы можем поставить её во все вызовы fetch , возможно, интегрировать в JavaScript-библиотеку нашего проекта, которая делает все запросы и внутри использует fetch .
Единственным отличием в поведении будет то, что для всех запросов на другой источник fetch будет посылать только источник в заголовке Referer (например, https://javascript.info , без пути). А для запросов на наш источник мы продолжим получать полный Referer (это может быть полезно для отладки).
Политика установки Referer (Referrer Policy) – не только для fetch
Политика установки Referer, описанная в спецификации Referrer Policy, существует не только для fetch , она более глобальная.
В частности, можно поставить политику по умолчанию для всей страницы, используя HTTP-заголовок Referrer-Policy , или на уровне ссылки .
mode
Опция mode – это защита от нечаянной отправки запроса на другой источник:
- «cors» – стоит по умолчанию, позволяет делать такие запросы так, как описано в Fetch: запросы на другие сайты,
- «same-origin» – запросы на другой источник запрещены,
- «no-cors» – разрешены только простые запросы на другой источник.
Эта опция может пригодиться, если URL-адрес для fetch приходит от третьей стороны, и нам нужен своего рода «глобальный выключатель» для запросов на другие источники.
credentials
Опция credentials указывает, должен ли fetch отправлять куки и авторизационные заголовки HTTP вместе с запросом.
- «same-origin» – стоит по умолчанию, не отправлять для запросов на другой источник,
- «include» – отправлять всегда, но при этом необходим заголовок Access-Control-Allow-Credentials в ответе от сервера, чтобы JavaScript получил доступ к ответу сервера, об этом говорилось в главе Fetch: запросы на другие сайты,
- «omit» – не отправлять ни при каких обстоятельствах, даже для запросов, сделанных в пределах текущего источника.
cache
По умолчанию fetch делает запросы, используя стандартное HTTP-кеширование. То есть, учитывается заголовки Expires , Cache-Control , отправляется If-Modified-Since и так далее. Так же, как и обычные HTTP-запросы.
Настройка cache позволяет игнорировать HTTP-кеш или же настроить его использование:
- «default» – fetch будет использовать стандартные правила и заголовки HTTP кеширования,
- «no-store» – полностью игнорировать HTTP-кеш, этот режим становится режимом по умолчанию, если присутствуют такие заголовки как If-Modified-Since , If-None-Match , If-Unmodified-Since , If-Match , или If-Range ,
- «reload» – не брать результат из HTTP-кеша (даже при его присутствии), но сохранить ответ в кеше (если это дозволено заголовками ответа);
- «no-cache» – в случае, если существует кешированный ответ – создать условный запрос, в противном же случае – обычный запрос. Сохранить ответ в HTTP-кеше,
- «force-cache» – использовать ответ из HTTP-кеша, даже если он устаревший. Если же ответ в HTTP-кеше отсутствует, сделать обычный HTTP-запрос, действовать как обычно,
- «only-if-cached» – использовать ответ из HTTP-кеша, даже если он устаревший. Если же ответ в HTTP-кеше отсутствует, то выдаётся ошибка. Это работает, только когда mode установлен в «same-origin» .
redirect
Обычно fetch прозрачно следует HTTP-редиректам, таким как 301, 302 и так далее.
Это можно поменять при помощи опции redirect :
- «follow» – стоит по умолчанию, следовать HTTP-редиректам,
- «error» – ошибка в случае HTTP-редиректа,
- «manual» – не следовать HTTP-редиректу, но установить адрес редиректа в response.url , а response.redirected будет иметь значение true , чтобы мы могли сделать перенаправление на новый адрес вручную.
integrity
Опция integrity позволяет проверить, соответствует ли ответ известной заранее контрольной сумме.
Как описано в спецификации, поддерживаемыми хеш-функциями являются SHA-256, SHA-384 и SHA-512. В зависимости от браузера, могут быть и другие.
Например, мы скачиваем файл, и мы точно знаем, что его контрольная сумма по алгоритму SHA-256 равна «abcdef» (разумеется, настоящая контрольная сумма будет длиннее).
Мы можем добавить это в настройку integrity вот так:
fetch('http://site.com/file', < integrity: 'sha256-abcdef' >);Затем fetch самостоятельно вычислит SHA-256 и сравнит его с нашей строкой. В случае несоответствия будет ошибка.
keepalive
Опция keepalive указывает на то, что запрос может «пережить» страницу, которая его отправила.
Например, мы собираем статистические данные о том, как посетитель ведёт себя на нашей странице (на что он кликает, части страницы, которые он просматривает), для анализа и улучшения интерфейса.
Когда посетитель покидает нашу страницу – мы хотим сохранить собранные данные на нашем сервере.
Для этого мы можем использовать событие window.onunload :
window.onunload = function() < fetch('/analytics', < method: 'POST', body: "statistics", keepalive: true >); >;Обычно, когда документ выгружается, все связанные с ним сетевые запросы прерываются. Но настройка keepalive указывает браузеру выполнять запрос в фоновом режиме даже после того, как пользователь покидает страницу. Поэтому эта опция обязательна, чтобы такой запрос удался.
У неё есть ряд ограничений:
- Мы не можем посылать мегабайты: лимит тела для запроса с keepalive – 64кб.
- Если мы собираем больше данных, можем отправлять их регулярно, «пакетами», тогда на момент последнего запроса в onunload их останется немного.
- Этот лимит распространяется на все запросы с keepalive . То есть, мы не можем его обойти, послав 100 запросов одновременно – каждый по 64Кбайт.
- Обычно сервер посылает пустой ответ на такие запросы, так что это не является проблемой.
Лучшие практики реферальной политики и реферальной политики
Оптимизируйте свои подборки Сохраняйте и классифицируйте контент в соответствии со своими настройками.
Рекомендации по настройке политики реферера и использованию реферера во входящих запросах.
Мод Налпас
Краткое содержание
- Неожиданная утечка информации из разных источников нарушает конфиденциальность веб-пользователей. Политика защитных рефералов может помочь.
- Рассмотрите возможность установки политики реферера strict-origin-when-cross-origin . Он сохраняет большую часть полезности реферера, одновременно снижая риск утечки данных из разных источников.
- Не используйте рефереры для защиты от подделки межсайтовых запросов (CSRF). Вместо этого используйте токены CSRF и другие заголовки в качестве дополнительного уровня безопасности.
Реферер и реферальная политика 101
HTTP-запросы могут включать дополнительный заголовок Referer , который указывает URL-адрес источника или веб-страницы, с которой был сделан запрос. Заголовок Referrer-Policy определяет, какие данные доступны в заголовке Referer .
В приведенном ниже примере заголовок Referer включает полный URL-адрес страницы site-one , с которой был сделан запрос.

Заголовок Referer может присутствовать в различных типах запросов:
- Навигационные запросы, когда пользователь нажимает ссылку
- Запросы подресурсов, когда браузер запрашивает изображения, iframe, скрипты и другие ресурсы, необходимые странице.
Для навигации и iframe доступ к этим данным также можно получить через JavaScript, используя document.referrer .
Значение Referer может быть информативным. Например, служба аналитики может использовать это значение, чтобы определить, что 50 % посетителей site-two.example пришли из social-network.example .
Но когда полный URL-адрес, включая путь и строку запроса, отправляется в Referer между источниками , это может препятствовать конфиденциальности и также представлять угрозу безопасности . Взгляните на эти URL-адреса:

URL-адреса с 1 по 5 содержат личную информацию, иногда даже идентифицирующую или конфиденциальную. Негласная утечка этих данных из разных источников может поставить под угрозу конфиденциальность веб-пользователей.
URL-адрес №6 — это URL-адрес возможности . Вы не хотите, чтобы он попал в руки кого-либо, кроме предполагаемого пользователя. Если это произойдет, злоумышленник сможет захватить учетную запись этого пользователя.
Чтобы ограничить доступ к данным реферера для запросов с вашего сайта, вы можете установить политику реферера.
Какие политики доступны и чем они отличаются?
Вы можете выбрать одну из восьми политик. В зависимости от политики данные, доступные из заголовка Referer (и document.referrer ), могут быть:

- Нет данных (отсутствует заголовок Referer )
- Только происхождение
- Полный URL-адрес: источник, путь и строка запроса.
Некоторые политики разработаны так, чтобы вести себя по-разному в зависимости от контекста : запроса между разными источниками или одного и того же источника, безопасности (независимо от того, является ли место назначения запроса таким же безопасным, как и источник), или того и другого. Это полезно для ограничения объема информации, передаваемой между источниками или для менее безопасных источников, сохраняя при этом богатство реферера на вашем собственном сайте.
Ниже приведен обзор, показывающий, как политики реферера ограничивают данные URL-адреса, доступные из заголовка Referer и document.referrer :

Что следует отметить:
- Все политики, которые учитывают эту схему (HTTPS или HTTP) ( strict-origin , no-referrer-when-downgrade и strict-origin-when-cross-origin ), обрабатывают запросы от источника HTTP к другому источнику HTTP одинаково. как запросы от источника HTTPS к другому источнику HTTPS, даже если HTTP менее безопасен. Это связано с тем, что для этих политик важно то, происходит ли понижение уровня безопасности, т. е. может ли запрос предоставить данные из зашифрованного источника в незашифрованный. Запрос HTTP → HTTP все время незашифрован, поэтому переход на более раннюю версию невозможен. HTTPS → HTTP-запросы, наоборот, представляют собой даунгрейд.
- Если запрос имеет значение Same-origin , это означает, что схема (HTTPS или HTTP) одинакова; следовательно, понижения уровня безопасности не происходит.
Политики рефералов по умолчанию в браузерах
По состоянию на октябрь 2021 г.
Если политика реферера не установлена, будет использоваться политика браузера по умолчанию.
Браузер Referrer-Policy по умолчанию Хром По умолчанию используется strict-origin-when-cross-origin . Fire Fox По умолчанию используется strict-origin-when-cross-origin .
Начиная с версии 93 , для пользователей строгой защиты от отслеживания и приватного просмотра: менее строгие политики реферера no-referrer-when-downgrade , origin-when-cross-origin и unsafe-url игнорируются для межсайтовых запросов, что означает, что реферер всегда обрезается для межсайтовых запросов, независимо от политики веб-сайта.Край По умолчанию используется strict-origin-when-cross-origin . Сафари Значение по умолчанию похоже на strict-origin-when-cross-origin с некоторыми особенностями. Подробности см. в разделе «Предотвращение отслеживания» . Настройка реферальной политики: лучшие практики
Цель: явно установить политику повышения конфиденциальности, например strict-origin-when-cross-origin (или более строгую).
Существуют различные способы установки политики рефералов для вашего сайта:
- В качестве HTTP-заголовка
- В вашем HTML
- Из JavaScript по каждому запросу
Вы можете установить разные политики для разных страниц, запросов или элементов.
HTTP-заголовок и мета-элемент находятся на уровне страницы. Порядок приоритета при определении эффективной политики элемента:
- Политика на уровне элемента
- Политика на уровне страницы
- Браузер по умолчанию
Пример:
Изображение будет запрошено с использованием политики no-referrer-when-downgrade , в то время как все остальные запросы подресурсов с этой страницы будут следовать политике strict-origin-when-cross-origin .
Как посмотреть политику рефералов?
Securityheaders.com удобен для определения политики, которую использует конкретный сайт или страница.
Вы также можете использовать инструменты разработчика Chrome, Edge или Firefox, чтобы просмотреть политику реферера, используемую для конкретного запроса. На момент написания этой статьи Safari не отображает заголовок Referrer-Policy , но показывает отправленный Referer .

Какую политику следует установить для своего веб-сайта?
Резюме: Явно установите политику повышения конфиденциальности, например strict-origin-when-cross-origin (или более строгую).
Почему «явно»?
Если политика реферера не установлена, будет использоваться политика браузера по умолчанию — фактически веб-сайты часто подчиняются политике браузера по умолчанию. Но это не идеально, потому что:
- Политиками браузера по умолчанию являются либо no-referrer-when-downgrade , strict-origin-when-cross-origin , либо более строгие — в зависимости от браузера и режима (частный/инкогнито). Таким образом, ваш веб-сайт не будет вести себя предсказуемо в разных браузерах.
- Браузеры принимают более строгие настройки по умолчанию, такие как strict-origin-when-cross-origin и такие механизмы, как обрезка реферера для запросов из разных источников. Явное согласие на политику повышения конфиденциальности до изменения настроек браузера по умолчанию дает вам контроль и помогает запускать тесты по вашему усмотрению.
Почему strict-origin-when-cross-origin (или более строгое)?
Вам нужна безопасная, повышающая конфиденциальность и полезная политика — что означает «полезная» зависит от того, чего вы хотите от реферера:
- Безопасность : если ваш веб-сайт использует HTTPS ( если нет, сделайте это приоритетом ), вы не хотите, чтобы URL-адреса вашего веб-сайта просачивались в запросы, отличные от HTTPS. Поскольку их может видеть любой в сети, это подвергнет ваших пользователей атакам «человек посередине». Политики no-referrer-when-downgrade , strict-origin-when-cross-origin , no-referrer и strict-origin решают эту проблему.
- Повышение конфиденциальности : для запроса из разных источников no-referrer-when-downgrade использует полный URL-адрес — это не является повышением конфиденциальности. strict-origin-when-cross-origin и strict-origin имеют общий только источник, а no-referrer вообще ничего не разделяет. В результате в качестве вариантов повышения конфиденциальности у вас останутся параметры strict-origin-when-cross-origin , strict-origin и no-referrer .
- Полезно : no-referrer и strict-origin никогда не используют полный URL-адрес, даже для запросов одного и того же источника, поэтому, если вам это нужно, strict-origin-when-cross-origin — лучший вариант.
Все это означает, что strict-origin-when-cross-origin как правило, является разумным выбором.
Пример: установка политики strict-origin-when-cross-origin :
Или на стороне сервера, например в Express:
const helmet = require('helmet'); app.use(helmet.referrerPolicy());Что, если strict-origin-when-cross-origin (или более строгое) не подходит для всех ваших вариантов использования?
В этом случае примените прогрессивный подход : установите для своего веб-сайта защитную политику, такую как strict-origin-when-cross-origin и, если необходимо, более либеральную политику для конкретных запросов или элементов HTML.
Пример: политика на уровне элемента
Обратите внимание, что Safari/WebKit может ограничивать document.referrer или заголовок Referer для межсайтовых запросов. Смотрите подробности .
Пример: политика уровня запроса
fetch(url, );Что еще следует учитывать?
Ваша политика должна зависеть от вашего веб-сайта и вариантов использования — это зависит от вас, вашей команды и вашей компании. Если некоторые URL-адреса содержат идентифицирующие или конфиденциальные данные, установите защитную политику.
Предупреждение. Данные, которые могут показаться вам не конфиденциальными, могут быть конфиденциальными для ваших пользователей или просто не являются данными, которые они хотят или ожидают, что они будут незаметно передаваться из разных источников.
Использование реферера из входящих запросов: лучшие практики
Что делать, если в функционале вашего сайта используется URL-адрес реферера входящих запросов?
Защитите данные пользователей
Referer может содержать частные, персональные или идентифицирующие данные, поэтому обязательно относитесь к ним соответствующим образом.
Имейте в виду, что полученный вами Referer может измениться.
Использование реферера из входящих запросов между источниками имеет несколько ограничений:
- Если у вас нет контроля над реализацией отправителя запроса, вы не можете делать предположения о полученном заголовке Referer (и document.referrer ). Отправитель запроса может в любой момент принять решение о переключении на политику no-referrer или, в более общем плане, на более строгую политику, чем та, которую он использовал раньше — это означает, что вы будете получать через Referer меньше данных, чем раньше.
- Браузеры по умолчанию все чаще используют Referrer-Policy strict-origin-when-cross-origin . Это означает, что теперь вы можете получать только источник (вместо полного URL-адреса реферера) во входящих запросах между источниками, если на сайте, который их отправляет, не установлена политика.
- Браузеры могут изменить способ управления Referer ; например, в будущем они могут решить всегда сокращать ссылки на источники в запросах подресурсов между источниками, чтобы защитить конфиденциальность пользователей.
- Заголовок Referer (и document.referrer ) может содержать больше данных, чем вам нужно, например полный URL-адрес, если вы хотите знать только, является ли запрос перекрестным.
Альтернативы Referer
Возможно, вам придется рассмотреть альтернативы, если:
- Важная функциональность вашего сайта использует URL-адрес реферера входящих запросов из разных источников;
- И/или если ваш сайт больше не получает ту часть URL-адреса реферера, которая ему нужна в запросе между источниками. Это происходит, когда отправитель запроса изменил свою политику или когда у него не установлена политика и изменилась политика браузера по умолчанию (как в Chrome 85 ).
Чтобы определить альтернативы, сначала проанализируйте, какую часть реферера вы используете.
Если вам нужен только источник ( https://site-one.example ):
- Если вы используете реферер в сценарии, который имеет доступ к странице верхнего уровня, альтернативой является window.location.origin .
- Заголовки, такие как Origin и Sec-Fetch-Site если они доступны, сообщают вам Origin или описывают, является ли запрос перекрестным, что может быть именно тем, что вам нужно.
Если вам нужны другие элементы URL-адреса (путь, параметры запроса…):
- Параметры запроса могут соответствовать вашему варианту использования, и это избавит вас от необходимости анализировать реферер.
- Если вы используете реферер в сценарии, который имеет доступ к странице верхнего уровня, альтернативой может быть window.location.pathname . Извлеките только раздел пути URL-адреса и передайте его в качестве аргумента, чтобы любая потенциально конфиденциальная информация в параметрах URL-адреса не передавалась.
Если вы не можете использовать эти альтернативы:
- Проверьте, можно ли изменить ваши системы, чтобы источник запроса ( site-one.example ) явно установил необходимую вам информацию в какой-либо конфигурации. Плюсы: более явно, более конфиденциально для пользователей site-one.example , более перспективно. Минус: потенциально больше работы с вашей стороны или для пользователей вашей системы.
- Проверьте, может ли сайт, отправляющий запросы, согласиться установить политику Referrer-Policy для каждого элемента или для каждого запроса no-referrer-when-downgrade . Минус: потенциально меньшая конфиденциальность для пользователей site-one.example , потенциально поддерживается не во всех браузерах.
Защита от подделки межсайтовых запросов (CSRF)
Обратите внимание, что отправитель запроса всегда может решить не отправлять реферер, установив политику no-referrer (и злоумышленник может даже подделать реферера).
Используйте токены CSRF в качестве основной защиты. Для дополнительной защиты используйте SameSite , а вместо Referer используйте такие заголовки, как Origin (доступно в запросах POST и CORS) и Sec-Fetch-Site (если доступно).
Ведение журнала
Обязательно защитите личные или конфиденциальные данные пользователей, которые могут находиться в Referer .
Если вы используете только источник, проверьте, может ли заголовок Origin быть альтернативой. Это может предоставить вам информацию, необходимую для целей отладки, более простым способом и без необходимости анализа реферера.
Платежи
Поставщики платежей могут полагаться на заголовок Referer входящих запросов для проверок безопасности.
- Пользователь нажимает кнопку «Купить» на online-shop.example/cart/checkout .
- online-shop.example перенаправляет на payment-provider.example для управления транзакцией.
- payment-provider.example проверяет Referer этого запроса на соответствие списку разрешенных значений Referer , установленному продавцами. Если он не соответствует ни одной записи в списке, payment-provider.example отклоняет запрос. Если оно совпадает, пользователь может перейти к транзакции.
Рекомендации по проверке безопасности потока платежей
Резюме: как поставщик платежей вы можете использовать Referer в качестве базовой проверки против наивных атак, но вам обязательно должен быть другой, более надежный метод проверки.
Сам по себе заголовок Referer не является надежным основанием для проверки: запрашивающий сайт, независимо от того, является ли он законным продавцом или нет, может установить политику no-referrer , которая сделает информацию Referer недоступной для платежного провайдера. Однако, как поставщику платежей, просмотр Referer может помочь вам поймать наивных злоумышленников, которые не установили политику no-referrer . Таким образом, вы можете решить использовать Referer в качестве первой базовой проверки. Если ты так сделаешь:
- Не ожидайте, что Referer всегда будет присутствовать; и если он присутствует, проверяйте только тот фрагмент данных, который он будет включать как минимум: origin . При настройке списка разрешенных значений Referer убедитесь, что в него не включен путь, а только начало координат. Пример: разрешенные значения Referer для online-shop.example должны быть online-shop.example , а не online-shop.example/cart/checkout . Почему? Поскольку, ожидая либо отсутствие Referer вообще, либо значение Referer , которое является источником запрашивающего веб-сайта, вы предотвращаете непредвиденные ошибки, поскольку вы не делаете предположений о Referrer-Policy установленной вашим продавцом, или о поведении браузера, если продавец политика не установлена. И сайт, и браузер могут отослать Referer , отправленный во входящем запросе, только к источнику или вообще не отправлять Referer .
- Если Referer отсутствует или присутствует и ваша базовая проверка происхождения Referer прошла успешно: вы можете перейти к другому, более надежному методу проверки (см. ниже).
Какой метод проверки более надежный?
Одним из надежных методов проверки является предоставление запрашивающей стороне возможности хешировать параметры запроса вместе с уникальным ключом. Как поставщик платежей вы можете затем вычислить тот же хэш на своей стороне и принять запрос только в том случае, если он соответствует вашим расчетам.
Что происходит с Referer , когда сайт продавца HTTP без политики реферера перенаправляется на поставщика платежей HTTPS?
Referer не будет виден в запросе к поставщику платежей HTTPS, поскольку большинство браузеров по умолчанию используют strict-origin-when-cross-origin или no-referrer-when-downgrade когда на веб-сайте не установлена политика. Также обратите внимание, что переход Chrome на новую политику по умолчанию не изменит этого поведения.
Примечание. Если ваш веб-сайт использует HTTP, перейдите на HTTPS .
Заключение
Политика защитных рефералов — отличный способ предоставить вашим пользователям больше конфиденциальности.
Чтобы узнать больше о различных методах защиты ваших пользователей, ознакомьтесь с коллекцией «Безопасно и надежно» на сайте web.dev!
Выражаем огромную благодарность за вклад и отзывы всем рецензентам, особенно Каустубхе Говинду, Дэвиду Ван Кливу, Майку Уэсту, Сэму Даттону, Роуэну Мервуду, Джкску и Кейси Баскес.
Ресурсы
- Понимание понятий «тот же сайт» и «тот же источник»
- Новый заголовок безопасности: Политика реферера (2017 г.)
- Реферальная политика на MDN
- Заголовок Referer: проблемы конфиденциальности и безопасности на MDN
- Изменение Chrome: намерение Blink реализовать
- Изменение Chrome: Blink намерен отправить
- Изменение Chrome: запись статуса
- Изменение Chrome: пост в блоге о бета-версии 85
- Реферер обрезает ветку GitHub: что делают разные браузеры
- Спецификация политики рефереров
Если не указано иное, контент на этой странице предоставляется по лицензии Creative Commons «С указанием авторства 4.0», а примеры кода – по лицензии Apache 2.0. Подробнее об этом написано в правилах сайта. Java – это зарегистрированный товарный знак корпорации Oracle и ее аффилированных лиц.
Последнее обновление: 2020-07-30 UTC.
CORS (Cross-Origin Resource Sharing)¶
Понятие CORS или «Cross-Origin Resource Sharing» относится к ситуациям, при которых запущенный в браузере фронтенд содержит JavaScript-код, который взаимодействует с бэкендом, находящимся на другом «источнике» («origin»).
Источник¶
Источник — это совокупность протокола ( http , https ), домена ( myapp.com , localhost , localhost.tiangolo.com ) и порта ( 80 , 443 , 8080 ).
Поэтому это три разных источника:
- http://localhost
- https://localhost
- http://localhost:8080
Даже если они все расположены в localhost , они используют разные протоколы и порты, а значит, являются разными источниками.
Шаги¶
Допустим, у вас есть фронтенд, запущенный в браузере по адресу http://localhost:8080 , и его JavaScript-код пытается взаимодействовать с бэкендом, запущенным по адресу http://localhost (поскольку мы не указали порт, браузер по умолчанию будет использовать порт 80 ).
Затем браузер отправит бэкенду HTTP-запрос OPTIONS , и если бэкенд вернёт соответствующие заголовки для авторизации взаимодействия с другим источником ( http://localhost:8080 ), то браузер разрешит JavaScript-коду на фронтенде отправить запрос на этот бэкенд.
Чтобы это работало, у бэкенда должен быть список «разрешённых источников» («allowed origins»).
В таком случае этот список должен содержать http://localhost:8080 , чтобы фронтенд работал корректно.
Подстановочный символ «*» ¶
В качестве списка источников можно указать подстановочный символ «*» («wildcard»), чтобы разрешить любые источники.
Но тогда не будут разрешены некоторые виды взаимодействия, включая всё связанное с учётными данными: куки, заголовки Authorization с Bearer-токенами наподобие тех, которые мы использовали ранее и т.п.
Поэтому, чтобы всё работало корректно, лучше явно указывать список разрешённых источников.
Использование CORSMiddleware ¶
Вы можете настроить этот механизм в вашем FastAPI приложении, используя CORSMiddleware .
- Импортируйте CORSMiddleware .
- Создайте список разрешённых источников (в виде строк).
- Добавьте его как «middleware» к вашему FastAPI приложению.
Вы также можете указать, разрешает ли ваш бэкенд использование:
- Учётных данных (включая заголовки Authorization, куки и т.п.).
- Отдельных HTTP-методов ( POST , PUT ) или всех вместе, используя «*» .
- Отдельных HTTP-заголовков или всех вместе, используя «*» .
from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware app = FastAPI() origins = [ "http://localhost.tiangolo.com", "https://localhost.tiangolo.com", "http://localhost", "http://localhost:8080", ] app.add_middleware( CORSMiddleware, allow_origins=origins, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) @app.get("/") async def main(): return "message": "Hello World">CORSMiddleware использует для параметров «запрещающие» значения по умолчанию, поэтому вам нужно явным образом разрешить использование отдельных источников, методов или заголовков, чтобы браузеры могли использовать их в кросс-доменном контексте.
Поддерживаются следующие аргументы:
- allow_origins — Список источников, на которые разрешено выполнять кросс-доменные запросы. Например, [‘https://example.org’, ‘https://www.example.org’] . Можно использовать [‘*’] , чтобы разрешить любые источники.
- allow_origin_regex — Регулярное выражение для определения источников, на которые разрешено выполнять кросс-доменные запросы. Например, ‘https://.*\.example\.org’ .
- allow_methods — Список HTTP-методов, которые разрешены для кросс-доменных запросов. По умолчанию равно [‘GET’] . Можно использовать [‘*’] , чтобы разрешить все стандартные методы.
- allow_headers — Список HTTP-заголовков, которые должны поддерживаться при кросс-доменных запросах. По умолчанию равно [] . Можно использовать [‘*’] , чтобы разрешить все заголовки. Заголовки Accept , Accept-Language , Content-Language и Content-Type всегда разрешены для простых CORS-запросов.
- allow_credentials — указывает, что куки разрешены в кросс-доменных запросах. По умолчанию равно False . Также, allow_origins нельзя присвоить [‘*’] , если разрешено использование учётных данных. В таком случае должен быть указан список источников.
- expose_headers — Указывает любые заголовки ответа, которые должны быть доступны браузеру. По умолчанию равно [] .
- max_age — Устанавливает максимальное время в секундах, в течение которого браузер кэширует CORS-ответы. По умолчанию равно 600 .
CORSMiddleware отвечает на два типа HTTP-запросов.
CORS-запросы с предварительной проверкой¶
Это любые OPTIONS запросы с заголовками Origin и Access-Control-Request-Method .
В этом случае middleware перехватит входящий запрос и отправит соответствующие CORS-заголовки в ответе, а также ответ 200 или 400 в информационных целях.
Простые запросы¶
Любые запросы с заголовком Origin . В этом случае middleware передаст запрос дальше как обычно, но добавит соответствующие CORS-заголовки к ответу.
Больше информации¶
Для получения более подробной информации о CORS , обратитесь к Документации CORS от Mozilla.
Вы также можете использовать from starlette.middleware.cors import CORSMiddleware .
FastAPI предоставляет несколько middleware в fastapi.middleware только для вашего удобства как разработчика. Но большинство доступных middleware взяты напрямую из Starlette.