Cors включить в браузере

Обновлено: 04.07.2024


Cross-origin resource sharing — технология современных браузеров, которая позволяет предоставить веб-странице доступ к ресурсам другого домена. В этой статье я расскажу об этой технологии, призванной обеспечить безопасность, или наоборот, поставить веб-приложение под удар.

Что такое CORS?

CORS — это механизм безопасности, который позволяет веб-странице из одного домена обращаться к ресурсу с другим доменом (кросс-доменным запросом). Без таких функций, как CORS, веб-сайты ограничиваются доступом к ресурсам одного и того же происхождения через так называемую политику единого происхождения.

Первым шагом в понимании CORS является знание того, как работают некоторые функции безопасности веб-браузеров. По умолчанию веб-браузеры не разрешают AJAX-запросы на сайты, кроме сайта, который вы посещаете. Это называется политикой единого происхождения, и это важная часть модели веб-безопасности. Совместное использование ресурсов между разными источниками (cross-origin resource sharing) — это механизм HTML 5, который дополняет политику единого происхождения для упрощения совместного использования ресурсов домена между различными веб-приложениями.

Спецификация CORS определяет набор заголовков, которые позволяют серверу и браузеру определять, какие запросы для междоменных ресурсов (изображения, таблицы стилей, сценарии, данные и т. д.) разрешены, а какие нет. CORS является техникой для ослабления правила одного источника, позволяя JavaScript на web странице обрабатывать REST API запросы от другого источника.

По своей сути, CORS это защитная оболочка для браузера. Совместное использование ресурсов между разными источниками очень важно в современном мире сложных веб-приложений, и все браузеры поддерживают его. В частности, CORS обычно используется для междоменных AJAX запросов.

Обмен запросами

Взаимодействие ресурсов начинается с отправки GET, POST или HEAD запросу к тому или иному ресурсу на сервере. Тип содержимого POST запроса ограничен application/x-www-form-urlencoded, multipart/form-data или plaintext. Запрос включает заголовок Origin, который и указывает на происхождение клиентского кода.

Веб приложение проверяет происхождение запроса и на основании Origin либо принимает запрос, либо отвергает его. Если запрос принят, запрашиваемые сервер ответит заголовком Access-Control-Allow-Origin. Этот заголовок будет указывать клиенту с каким происхождением будет разрешен доступ. Принимая во внимание, что Access-Control-Allow-Origin соответствует Origin запроса, браузер разрешит запрос.

Access-Control-Max-Age указывает время жизни предзапроса (также он называется "предполетным") доступности того или иного метода, после которого должен быть выполнен новый запрос на тот или иной метод.

Отказ от политики запроса из белого списка

Использование правильных заголовков, методов и доверенных доменов вроде бы не позволяет злоумышленнику вклиниться в эту цепочку обмена. На самом деле это не так. И подводит здесь коварная *.

Наиболее распространенная проблема безопасности при внедрении CORS — это отказ от проверки запроса белых списков. Зачастую разработчики устанавливают значение для Access-Control-Allow-Origin в '*'. Это позволяет любому домену в Интернете получать доступ к ресурсам этого сайта.

Основания проблема кроется в том, что многие компании размещают API в пределах домена, не ограничивания к нему доступ политикой "белого списка". Это порождает уязвимость.

Attack scenario

Наглядные примеры

В качестве примера приведу код OWASP Testing Guide. Уязвимое веб-приложение, с неверно настроенной политикой Access-Control-Allow-Origin.

Например, такой запрос будет показывать содержимое файла profile.php:

Т.к. отсутствует проверка URL-адреса, атакующий может добавить скрипт, который будет выполняться в контексте домена example.foo со следующим URL:

image

Защитные меры

Указывайте конкретные методы обращения.

Не используйте wildcard — CORS учитывает или * или домен.

Обязательно указывайте протокол. "Access-Control-Allow-Origin: site.ru" не будет учтён, поскольку протокол отсутствует.

При использовании Access-Control-Allow-Credentials: true всегда используется Access-Control-Allow-Origin: домен — при использовании * браузер не получит ответ.


Каждому разработчику приходилось сталкиваться с ошибкой Access to fetched has been blocked by CORS policy . Существует несколько способов быстрого решения данной проблемы. Однако, давайте не будем спешить и подробно рассмотрим, что из себя представляет политика CORS.

Отлично! Мы только что отправили запрос на сервер и получили в ответ данные в формате JSON.

Что случилось? Мы отправили точно такой же запрос, но на этот раз браузер показывает какую-то ошибку.

Мы наблюдаем CORS в действии. Почему возникла данная ошибка и что она означает?

Политика общего происхождения

Источник является другим, когда он расположен в другом (под)домене, протоколе или порте.


Круто, но зачем нужна ПОП?

Предположим, что ее не существует, и вы случайно кликаете по вирусной ссылке, которую прислала ваша тетя в Facebook. Данная ссылка перенаправляет вас на «вредоносный сайт», имеющий встроенный iframe, который загружает сайт вашего банка и успешно авторизуется там с помощью куки.

Разработчики «злого сайта» позаботились о том, чтобы он имел доступ к iframe и мог взаимодействовать с содержимым DOM сайта вашего банка для перечисления денежных средств на свой аккаунт от вашего имени.

Да уж… это серьезная проблема безопасности. Мы не хотим, чтобы кто-нибудь имел доступ к чему-либо без нашего ведома.

К счастью, существует ПОП. Эта политика ограничивает доступ к ресурсам из других источников.

Хорошо, но… как это работает?

CORS на стороне клиента

Несмотря на то, что ПОП применяется только к скриптам, браузеры «расширяют» ее до любых JavaScript-запросов: по умолчанию мы имеем доступ только к ресурсам из одного источника.

Хм, но… у нас часто возникает необходимость получить ресурсы из другого источника. Возможно, нашему фронтенду нужно обратиться к серверному прикладному интерфейсу для загрузки данных. Для безопасного получения ресурсов из других источников браузеры реализуют механизм под названием CORS.

CORS расшифровывается как Cross-Origin Resource Sharing (совместное использование ресурсов). Хотя браузеры запрещают получение ресурсов из других источников, мы можем использовать CORS для изменения этого ограничения, оставаясь при этом в безопасности.

Для того, чтобы браузер разрешил получение ресурсов из другого источника, в ответе сервера также должен содержаться определенный заголовок.

CORS на стороне сервера

Как разработчики серверной части приложения, мы можем разрешить получение наших ресурсов другими источниками посредством включения в ответ специальных заголовков, начинающихся с Access-Control-* . На основе значения таких заголовков браузер разрешает совместное использование ресурсов.

Существует несколько CORS-заголовков, но один из них является обязательным: Access-Control-Allow-Origin .

Значение данного заголовка определяет, какие источники могут получать наши ресурсы.

Механизм CORS, реализованный в браузере, проверяет совпадение значений заголовка ответа Access-Control-Allow-Origin и заголовка запроса Origin .

Отлично. Теперь мы можем получать ресурсы из других источников. Что произойдет, если мы попытаемся сделать это из источника, не указанного в Access-Control-Allow-Origin ?

Да, CORS заблокировал доступ к ресурсам.

CORS позволяет указать * в качестве значения разрешенных источников. Это означает, что ресурсы будут доступны любым источникам, так что будьте осторожны.

Access-Control-Allow-Origin — это один из многих заголовков, которые мы можем установить. Разработчик серверной части может настраивать CORS для разрешения (запрета) конкретных запросов.

Другим распространенным заголовком является Access-Control-Allow-Methods . CORS разрешает только те запросы из других источников, которые были отправлены с помощью указанных методов.

В данном случае разрешены только запросы, отправленные с помощью методов GET, POST или PUT. Другие методы, такие как PATCH или DELETE будут заблокированы.

Говоря о запросах, отправленных с помощью методов PUT, PATCH и DELETE, CORS обрабатывает их особым образом. Эти «непростые» запросы иногда называют предварительными (preflight).

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

CORS работает с двумя типами запросов: простыми и предварительными. То, каким является запрос, зависит от некоторых его значений.

Запрос является простым, если он отправлен с помощью методов GET или POST и не содержит дополнительных заголовков. Любой другой запрос является предварительным.

Хорошо, но что означает предварительный запрос и зачем нужны такие запросы?

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

Сервер получает предварительный запрос и отправляет пустой предварительный ответ, содержащий CORS-заголовки. Браузер получает предварительный ответ и проверяет, будет ли разрешен фактический запрос.

Если да, то браузер отправляет фактический запрос и получает данные в ответ.

Если нет, CORS заблокирует предварительный запрос и фактический запрос не будет отправлен. Предварительные запросы — это отличный способ предотвратить доступ и изменение ресурсов на сервере. Это защищает сервер от потенциально нежелательных запросов из других источников.

Для уменьшения количества повторных запросов мы можем закэшировать предварительный ответ посредством добавления заголовка Access-Control-Max-Age в CORS-запрос. Это позволяет избежать повторного направления предварительного запроса.

Полномочия (credentials)

Куки, заголовки авторизации и сертификаты TLS по умолчанию устанавливаются только для запросов из одного источника. Однако у нас может возникнуть необходимость использовать эти полномочия в запросе из другого источника. Возможно, мы хотим включить в запрос куки, которые сервер может использовать для идентификации пользователя.

Хотя CORS не содержит полномочий по умолчанию, мы можем изменить это с помощью заголовка Access-Control-Allow-Credentials .

Если мы хотим включить куки и другие заголовки авторизации в наш запрос из другого источника, нам нужно присвоить полю withCredentials значение true в запросе и добавить заголовок Access-Control-Allow-Credentials в ответ.

Готово, теперь мы можем включать полномочия в наши запросы из другого источника.

Параметры безопасности веб-браузера предотвращают отправку запросов AJAX с веб-страницы к другому домену. Это ограничение называется политикой того же происхождения и предотвращает чтение вредоносных данных с другого сайта злоумышленником. Однако иногда может потребоваться разрешить другим сайтам вызывать веб-API.

Общий доступ к ресурсам в разных источниках (CORS) — это стандарт консорциума W3C, позволяющий серверу смягчить ту же политику. С помощью CORS сервер может явным образом разрешить некоторые запросы независимо от источника, а другие — отклонить. CORS безопаснее и более гибкий, чем более ранние методики, такие как JSONP. В этом руководстве показано, как включить CORS в приложении веб-API.

Программное обеспечение, используемое в этом руководстве

Введение

Показывает веб-службу и веб-клиент

Что такое "тот же источник"?

Два URL-адреса имеют один и тот же источник, если они имеют идентичные схемы, узлы и порты. (RFC 6454)

Эти два URL-адреса имеют один и тот же источник:

Эти URL-адреса имеют разные источники, отличные от предыдущих двух:

При сравнении источников Internet Explorer не учитывает порт.

Создание проекта WebService

Диалоговое окно создания проекта ASP.NET в Visual Studio

Добавьте контроллер веб-API TestController с именем и следующим кодом:

Создание проекта WebClient

Шаблон MVC в диалоговом окне создания проекта ASP.NET в Visual Studio

В Обозреватель решений откройте файл Views/Home/Index. cshtml. Замените код в этом файле следующим кодом:

Для переменной serviceUrl используйте URI приложения WebService.

Запустите приложение WebClient локально или опубликуйте его на другом веб-сайте.

Ошибка "попробовать" в браузере

Веб-отладчик Fiddler, отображающий веб-запросы

Включение CORS

Теперь включите CORS в приложении WebService. Сначала добавьте пакет NuGet для CORS. В Visual Studio в меню Сервис выберите Диспетчер пакетов NuGet, а затем выберите консоль диспетчера пакетов. В окне консоли диспетчера пакетов введите следующую команду:

Эта команда устанавливает последний пакет и обновляет все зависимости, включая основные библиотеки веб-API. Используйте -Version флаг, чтобы выбрать конкретную версию. Для пакета CORS требуется веб-API 2,0 или более поздней версии.

Откройте файл app _ Start/WebApiConfig. CS. Добавьте следующий код в метод WebApiConfig. Register :

Затем добавьте атрибут [EnableCors] в TestController класс:

В качестве параметра происхождения используйте URI, в котором развернуто приложение WebClient. Это позволяет выполнять запросы между источниками от WebClient, не разрешая все остальные междоменные запросы. Позже я опишу параметры для [EnableCors] более подробно.

Не включайте косую черту в конце URL-адреса происхождения .

Повторно разверните обновленное приложение WebService. Обновлять WebClient не требуется. Теперь запрос AJAX от WebClient должен быть выполнен. Методы GET, WHERE и POST разрешены.

Принцип работы CORS

Ниже приведен пример запроса между источниками. Заголовок "Origin" предоставляет домен сайта, выполняющего запрос.

Если сервер разрешает запрос, он устанавливает заголовок Access-Control-Allow-Origin. Значение этого заголовка либо соответствует заголовку источника, либо является подстановочным значением « * », что означает, что любой источник разрешен.

Если ответ не включает заголовок Access-Control-Allow-Origin, то запрос AJAX завершается ошибкой. В частности, браузер не разрешает запрос. Даже если сервер возвращает успешный ответ, браузер не делает ответ доступным клиентскому приложению.

Предпечатные запросы

Для некоторых запросов CORS браузер отправляет дополнительный запрос, называемый «предварительным запросом», перед отправкой фактического запроса ресурса.

Браузер может пропустить Предпечатный запрос, если выполняются следующие условия.

Метод запроса — GET, HEAD или POST, а

Приложение не устанавливает никаких заголовков запроса, кроме Accept, Accept-Language, Content-Language, Content-Type или Last-Event-ID, и

Заголовок Content-Type (если задан) является одним из следующих:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

Ниже приведен пример предпечатного запроса:

Ниже приведен пример ответа, предполагая, что сервер разрешает запрос:

Ответ содержит заголовок Access-Control-Allow-Methods, в котором перечислены допустимые методы и при необходимости заголовок Access-Control-Allow-Headers, который перечисляет разрешенные заголовки. Если Предпечатный запрос выполнен, браузер отправляет фактический запрос, как описано выше.

Средства, обычно используемые для тестирования конечных точек с запросами параметров предварительной проверки (например, Fiddler и POST), не отправляют обязательные заголовки параметров по умолчанию. Убедитесь, что Access-Control-Request-Method Access-Control-Request-Headers заголовки и отправляются с запросом, а заголовки параметров достигают приложения через IIS.

Удаление OPTIONSVerbHandler предотвращает обработку запросов параметров службами IIS. Замена ExtensionlessUrlHandler-Integrated-4.0 разрешает запросы параметров для доступа к приложению, так как регистрация модуля по умолчанию разрешает только запросы GET, Head, POST и Debug с URL-адресами без расширений.

Правила области для [EnableCors]

Можно включить CORS для каждого действия, для каждого контроллера или глобально для всех контроллеров веб-API в приложении.

За действие

Чтобы включить CORS для одного действия, установите атрибут [EnableCors] в методе действия. В следующем примере показано включение CORS GetItem только для метода.

На контроллер

Если задать [EnableCors] в классе контроллера, он будет применяться ко всем действиям на контроллере. Чтобы отключить CORS для действия, добавьте к действию атрибут [дисаблекорс] . В следующем примере показано включение CORS для каждого метода, за исключением PutItem .

Глобально

Чтобы включить CORS для всех контроллеров веб-API в приложении, передайте экземпляр енаблекорсаттрибуте в метод EnableCors :

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

  1. Действие
  2. Контроллер
  3. Глобальный

Установка разрешенных источников

Параметр Origins атрибута [EnableCors] указывает, каким источникам разрешен доступ к ресурсу. Значение представляет собой разделенный запятыми список разрешенных источников.

Можно также использовать подстановочное значение " * ", чтобы разрешить запросы от любых источников.

Следует тщательно продуматьсь перед разрешением запросов из любого источника. Это означает, что буквально любой веб-сайт может выполнять вызовы AJAX к веб-API.

Задание разрешенных заголовков запроса

Однако браузеры не полностью согласуются с тем, как они устанавливают заголовки Access-Control-request-headers. Например, Chrome в настоящее время включает "источник". FireFox не включает стандартные заголовки, такие как "Accept", даже если приложение задает их в скрипте.

Если для заголовков заданы любые значения, отличные от " * ", следует включить по меньшей мере "Accept", "Content-Type" и "Origin", а также любые настраиваемые заголовки, которые требуется поддерживать.

Задание разрешенных заголовков ответа

  • Cache-Control;
  • Content-Language;
  • Content-Type
  • Expires
  • Last-Modified
  • Включают

Спецификация CORS вызывает эти простые заголовки ответа. Чтобы сделать другие заголовки доступными для приложения, задайте параметр exposedHeaders [EnableCors].

В следующем примере Get метод контроллера задает пользовательский заголовок с именем "X-Custom-Header". По умолчанию браузер не будет предоставлять этот заголовок в запросе между источниками. Чтобы сделать заголовок доступным, включите "X-Custom-Header" в exposedHeaders.

Передача учетных данных в запросах между источниками

Кроме того, сервер должен разрешать учетные данные. Чтобы разрешить учетные данные для разных источников в веб-API, задайте для свойства суппортскредентиалс атрибута [EnableCors] значение true:

Если браузер отправляет учетные данные, но ответ не включает допустимый заголовок Access-Control-Allow-Credential, браузер не будет предоставлять ответ приложению, а запрос AJAX завершится ошибкой.

Пользовательские поставщики политик CORS

Атрибут [EnableCors] реализует интерфейс икорсполиципровидер . Вы можете предоставить собственную реализацию, создав класс, производный от Attribute , и реализующий икорсполиципровидер.

Теперь можно применить атрибут в любом месте, которое вы бы поместили [EnableCors].

Например, Пользовательский поставщик политики CORS может считывать параметры из файла конфигурации.

В качестве альтернативы использованию атрибутов можно зарегистрировать объект икорсполиципровидерфактори , создающий объекты икорсполиципровидер .

Чтобы задать икорсполиципровидерфактори, вызовите метод расширения сеткорсполиципровидерфактори при запуске, как показано ниже.

Поддержка браузеров

Пакет CORS веб-API — это технология на стороне сервера. Браузер пользователя также должен поддерживать CORS. К счастью, текущие версии всех основных браузеров включают поддержку CORS.

Browser security prevents a web page from making AJAX requests to another domain. This restriction is called the same-origin policy, and prevents a malicious site from reading sensitive data from another site. However, sometimes you might want to let other sites call your web API.

Cross Origin Resource Sharing (CORS) is a W3C standard that allows a server to relax the same-origin policy. Using CORS, a server can explicitly allow some cross-origin requests while rejecting others. CORS is safer and more flexible than earlier techniques such as JSONP. This tutorial shows how to enable CORS in your Web API application.

Software used in the tutorial

Introduction

Shows web service and web client

What is "same origin"?

Two URLs have the same origin if they have identical schemes, hosts, and ports. (RFC 6454)

These two URLs have the same origin:

These URLs have different origins than the previous two:

Internet Explorer does not consider the port when comparing origins.

Create the WebService project

New ASP.NET project dialog in Visual Studio

Add a Web API controller named TestController with the following code:

Web browser showing test message

Create the WebClient project

MVC template in New ASP.NET Project dialog in Visual Studio

In Solution Explorer, open the file Views/Home/Index.cshtml. Replace the code in this file with the following:

For the serviceUrl variable, use the URI of the WebService app.

Run the WebClient app locally or publish it to another website.


Fiddler web debugger showing web requests

Enable CORS

Now let's enable CORS in the WebService app. First, add the CORS NuGet package. In Visual Studio, from the Tools menu, select NuGet Package Manager, then select Package Manager Console. In the Package Manager Console window, type the following command:

This command installs the latest package and updates all dependencies, including the core Web API libraries. Use the -Version flag to target a specific version. The CORS package requires Web API 2.0 or later.

Open the file App_Start/WebApiConfig.cs. Add the following code to the WebApiConfig.Register method:

Next, add the [EnableCors] attribute to the TestController class:

For the origins parameter, use the URI where you deployed the WebClient application. This allows cross-origin requests from WebClient, while still disallowing all other cross-domain requests. Later, I'll describe the parameters for [EnableCors] in more detail.

Do not include a forward slash at the end of the origins URL.

Redeploy the updated WebService application. You don't need to update WebClient. Now the AJAX request from WebClient should succeed. The GET, PUT, and POST methods are all allowed.

Web browser showing successful test message

How CORS Works

Here is an example of a cross-origin request. The "Origin" header gives the domain of the site that is making the request.

If the server allows the request, it sets the Access-Control-Allow-Origin header. The value of this header either matches the Origin header, or is the wildcard value "*", meaning that any origin is allowed.

If the response does not include the Access-Control-Allow-Origin header, the AJAX request fails. Specifically, the browser disallows the request. Even if the server returns a successful response, the browser does not make the response available to the client application.

Preflight Requests

For some CORS requests, the browser sends an additional request, called a "preflight request", before it sends the actual request for the resource.

The browser can skip the preflight request if the following conditions are true:

The request method is GET, HEAD, or POST, and

The application does not set any request headers other than Accept, Accept-Language, Content-Language, Content-Type, or Last-Event-ID, and

The Content-Type header (if set) is one of the following:

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

Here is an example of a preflight request:

Here is an example response, assuming that the server allows the request:

The response includes an Access-Control-Allow-Methods header that lists the allowed methods, and optionally an Access-Control-Allow-Headers header, which lists the allowed headers. If the preflight request succeeds, the browser sends the actual request, as described earlier.

Tools commonly used to test endpoints with preflight OPTIONS requests (for example, Fiddler and Postman) don't send the required OPTIONS headers by default. Confirm that the Access-Control-Request-Method and Access-Control-Request-Headers headers are sent with the request and that OPTIONS headers reach the app through IIS.

The removal of OPTIONSVerbHandler prevents IIS from handling OPTIONS requests. The replacement of ExtensionlessUrlHandler-Integrated-4.0 allows OPTIONS requests to reach the app because the default module registration only allows GET, HEAD, POST, and DEBUG requests with extensionless URLs.

Scope Rules for [EnableCors]

You can enable CORS per action, per controller, or globally for all Web API controllers in your application.

Per Action

To enable CORS for a single action, set the [EnableCors] attribute on the action method. The following example enables CORS for the GetItem method only.

Per Controller

If you set [EnableCors] on the controller class, it applies to all the actions on the controller. To disable CORS for an action, add the [DisableCors] attribute to the action. The following example enables CORS for every method except PutItem .

Globally

To enable CORS for all Web API controllers in your application, pass an EnableCorsAttribute instance to the EnableCors method:

If you set the attribute at more than one scope, the order of precedence is:

Set the allowed origins

The origins parameter of the [EnableCors] attribute specifies which origins are allowed to access the resource. The value is a comma-separated list of the allowed origins.

You can also use the wildcard value "*" to allow requests from any origins.

Consider carefully before allowing requests from any origin. It means that literally any website can make AJAX calls to your web API.

Set the allowed request headers

However, browsers are not entirely consistent in how they set Access-Control-Request-Headers. For example, Chrome currently includes "origin". FireFox does not include standard headers such as "Accept", even when the application sets them in script.

If you set headers to anything other than "*", you should include at least "accept", "content-type", and "origin", plus any custom headers that you want to support.

Set the allowed response headers

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

The CORS spec calls these simple response headers. To make other headers available to the application, set the exposedHeaders parameter of [EnableCors].

In the following example, the controller's Get method sets a custom header named ‘X-Custom-Header'. By default, the browser will not expose this header in a cross-origin request. To make the header available, include ‘X-Custom-Header' in exposedHeaders.

Pass credentials in cross-origin requests

In addition, the server must allow the credentials. To allow cross-origin credentials in Web API, set the SupportsCredentials property to true on the [EnableCors] attribute:

If the browser sends credentials, but the response does not include a valid Access-Control-Allow-Credentials header, the browser will not expose the response to the application, and the AJAX request fails.

Be careful about setting SupportsCredentials to true, because it means a website at another domain can send a logged-in user's credentials to your Web API on the user's behalf, without the user being aware. The CORS spec also states that setting origins to "*" is invalid if SupportsCredentials is true.

Custom CORS policy providers

The [EnableCors] attribute implements the ICorsPolicyProvider interface. You can provide your own implementation by creating a class that derives from Attribute and implements ICorsPolicyProvider.

Now you can apply the attribute any place that you would put [EnableCors].

For example, a custom CORS policy provider could read the settings from a configuration file.

As an alternative to using attributes, you can register an ICorsPolicyProviderFactory object that creates ICorsPolicyProvider objects.

To set the ICorsPolicyProviderFactory, call the SetCorsPolicyProviderFactory extension method at startup, as follows:

Browser support

The Web API CORS package is a server-side technology. The user's browser also needs to support CORS. Fortunately, the current versions of all major browsers include support for CORS.


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

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

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

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

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

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

Некоторые запросы не заставляют срабатывать CORS preflight. Они называются “простыми запросами” в данной статье, хотя Fetch спецификация, определяющая CORS, не использует этот термин. Запрос, для которого не срабатывает CORS preflight— так называемый “простой запросы”—это запрос, удовлетворяющий следующим условиям:

  • Допустимые методы для запроса:
  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain
Замечание: 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. Во всех других браузерах подобных дополнительных ограничений нет, потому что они не являются частью спецификации.

Это приведёт к простому обмену запросами между клиентом и сервером, используя CORS заголовки для обработки привилегий:


Посмотрим, что браузер отправит в таком случае на сервер, а также проверим ответ сервера:

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

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

  • Если в запросе используется любой из следующих методов:
  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

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


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

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

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

Заголовок 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-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 больше.

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

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

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

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

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

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

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

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

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


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

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

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

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

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

Access-Control-Allow-Origin

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

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

Если сервер возвращает название хоста, вместо "*", также может быть указан заголовок 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:

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.

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

An example of a preflight request is given above, including an example which sends this header to the browser.

Access-Control-Allow-Headers

Origin

The Origin header indicates the origin of the cross-site access request or preflight request.

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.

Note: 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

Examples of this usage can be found above.

Access-Control-Request-Headers

Читайте также: