Перейти к содержимому

Strict origin when cross origin что это

  • автор:

Атрибут referrerpolicy

Атрибут referrerpolicy определяет, какие реферальные данные следует отправлять при переходе по ссылке в заголовке Referer.

Заголовок Referer в HTTP-запросе содержит адрес страницы, с которой был выполнен переход на текущий адрес. Например, если пользователь перешел со страницы https://webref.ru/html/a на другой сайт, то в запросе будет следующий заголовок:

https://webref.ru/html/a

Заголовок Referer может применяться для следующих задач:

  • аналитика, откуда на сайт приходят пользователи;
  • определение популярных веб-страниц для входа;
  • сбор статистики по переходам между страницами сайта;
  • проверка, что запрос пришел с того же сайта;
  • ограничение доступа к содержимому с определённых адресов.

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

https://webref.ru/example/handler.php?login=Вася&password=12345

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

Синтаксис

Значения

no-referrer Заголовок Referer не отправляется. no-referrer-when-downgrade Заголовок Referer не отправляется при переходе с защищённого протокола на обычный (HTTPS→HTTP). same-origin Реферальные данные отправляются в пределах одного сайта, при переходе на другой сайт данные не передаются. origin Реферальные данные ограничены и включают только протокол, адрес сайта и порт, если он указан (https://example.com:80). strict-origin Реферальные данные включают протокол, адрес сайта и порт (при его наличии). Сами данные передаются только в рамках одного и того же протокола (HTTPS→HTTPS) и не отправляются при переходе на менее безопасный (HTTPS→HTTP). origin-when-cross-origin В рамках одного сайта передаётся полный путь. При переходе на другой сайт реферальные данные ограничены и включают только протокол, адрес сайта и порт. strict-origin-when-cross-origin Передаёт полный путь в рамках одного сайта, на другой сайт передаётся протокол, адрес сайта и порт, но только когда протокол остаётся прежним (HTTPS → HTTPS). Заголовок не передаётся при переходе на менее безопасный протокол (HTTPS→HTTP). unsafe-url Реферальные данные включают полный адрес документа. Это значение считается небезопасным.

Значение по умолчанию

Пример

Браузеры

79 51 38 14 50
51 50 41 14

В таблице браузеров применяются следующие обозначения.

  • — элемент полностью поддерживается браузером;
  • — элемент браузером не воспринимается и игнорируется;
  • — при работе возможно появление различных ошибок, либо элемент поддерживается с оговорками.

Число указывает версию браузреа, начиная с которой элемент поддерживается.

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 типа запросов:

  1. Запрос на тот же источник.
  2. Запрос на другой источник.
  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Кбайт.
    • Обычно сервер посылает пустой ответ на такие запросы, так что это не является проблемой.

    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.

    Включение запросов между источниками в веб-API ASP.NET 2

    Это содержимое предназначено для предыдущей версии .NET. Новая разработка должна использовать ASP.NET Core. Дополнительные сведения об использовании веб-API и запросов между источниками (CORS) в ASP.NET Core см. в разделе:

    • Учебник. Создание веб-API с помощью ASP.NET Core
    • Включение запросов CORS в ASP.NET Core

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

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

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

    • Visual Studio
    • Веб-API 2.2

    Введение

    В этом руководстве демонстрируется поддержка CORS в веб-API ASP.NET. Начнем с создания двух ASP.NET проектов: один называется «WebService», в котором размещается контроллер веб-API, а другой — «WebClient», который вызывает WebService. Так как два приложения размещаются в разных доменах, запрос AJAX от WebClient к WebService является запросом между источниками.

    Отображение веб-службы и веб-клиента

    Что такое «одно и то же происхождение»?

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

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

    • http://example.com/foo.html
    • http://example.com/bar.html

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

    • http://example.net — другой домен
    • http://example.com:9000/foo.html — другой порт
    • https://example.com/foo.html — другая схема
    • http://www.example.com/foo.html — другой поддомен

    Интернет-Обозреватель не учитывает порт при сравнении источников.

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

    В этом разделе предполагается, что вы уже знаете, как создавать проекты веб-API. Если нет, см. раздел начало работы с веб-API ASP.NET.

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

    1. Запустите Visual Studio и создайте проект веб-приложения ASP.NET (платформа .NET Framework).
    2. В диалоговом окне Новое веб-приложение ASP.NET выберите пустой шаблон проекта. В разделе Добавление папок и основных ссылок для установите флажок Веб-API .
    3. Добавьте контроллер TestController веб-API со следующим кодом:
    using System.Net.Http; using System.Web.Http; namespace WebService.Controllers < public class TestController : ApiController < public HttpResponseMessage Get() < return new HttpResponseMessage() < Content = new StringContent("GET: Test message") >; > public HttpResponseMessage Post() < return new HttpResponseMessage() < Content = new StringContent("POST: Test message") >; > public HttpResponseMessage Put() < return new HttpResponseMessage() < Content = new StringContent("PUT: Test message") >; > > > 

    В веб-браузере отображается тестовое сообщение

  • Приложение можно запустить локально или развернуть в Azure. (Для снимков экрана в этом руководстве приложение развертывается в Служба приложений Azure веб-приложения.) Чтобы убедиться, что веб-API работает, перейдите по адресу http://hostname/api/test/ , где hostname — это домен, в котором развернуто приложение. Вы увидите текст ответа «GET: тестовое сообщение».
  • Создание проекта WebClient

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

    1. Создайте другой проект веб-приложения ASP.NET (платформа .NET Framework) и выберите шаблон проекта MVC. При необходимости выберите Изменить проверку подлинности>без проверки подлинности. Для работы с этим руководством проверка подлинности не требуется.
    2. В Обозреватель решений откройте файл Views/Home/Index.cshtml. Замените код в этом файле следующим кодом:
     
    (Result)
    @section scripts < >

    При нажатии кнопки «Попробовать» запрос AJAX отправляется в приложение WebService с помощью метода HTTP, указанного в раскрывающемся списке (GET, POST или PUT). Это позволяет изучить различные запросы между источниками. В настоящее время приложение WebService не поддерживает CORS, поэтому при нажатии кнопки появится сообщение об ошибке.

    Ошибка

    Если вы watch HTTP-трафик в таком инструменте, как Fiddler, вы увидите, что браузер отправляет запрос GET, и запрос будет выполнен успешно, но вызов AJAX возвращает ошибку. Важно понимать, что политика одного источника не запрещает браузеру отправлять запрос. Вместо этого приложение не видит ответ.

    Веб-отладчик Fiddler с веб-запросами

    Включение CORS

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

    Install-Package Microsoft.AspNet.WebApi.Cors 

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

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

    using System.Web.Http; namespace WebService < public static class WebApiConfig < public static void Register(HttpConfiguration config) < // New code config.EnableCors(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api//", defaults: new < >); > > > 

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

    using System.Net.Http; using System.Web.Http; using System.Web.Http.Cors; namespace WebService.Controllers < [EnableCors(origins: "http://mywebclient.azurewebsites.net", headers: "*", methods: "*")] public class TestController : ApiController < // Controller methods not shown. >> 

    Для параметра origins используйте универсальный код ресурса (URI), в котором развернуто приложение WebClient. Это позволяет выполнять междоменные запросы из WebClient, но по-прежнему запрещает все остальные междоменные запросы. Далее я подробно опишу параметры для [EnableCors] .

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

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

    Веб-браузер с сообщением об успешном тестировании

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

    В этом разделе описывается, что происходит в запросе CORS на уровне HTTP-сообщений. Важно понимать, как работает CORS, чтобы можно было правильно настроить атрибут [EnableCors] и устранить неполадки, если все работает неправильно.

    В спецификации CORS представлено несколько новых заголовков HTTP, которые позволяют выполнять запросы между источниками. Если браузер поддерживает CORS, он автоматически задает эти заголовки для запросов между источниками; Вам не нужно выполнять никаких специальных действий в коде JavaScript.

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

    GET http://myservice.azurewebsites.net/api/test HTTP/1.1 Referer: http://myclient.azurewebsites.net/ Accept: */* Accept-Language: en-US Origin: http://myclient.azurewebsites.net Accept-Encoding: gzip, deflate User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0) Host: myservice.azurewebsites.net 

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

    HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Type: text/plain; charset=utf-8 Access-Control-Allow-Origin: http://myclient.azurewebsites.net Date: Wed, 05 Jun 2013 06:27:30 GMT Content-Length: 17 GET: Test message 

    Если ответ не содержит заголовок 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

      Правило о заголовках запросов применяется к заголовкам, которые приложение задает путем вызова setRequestHeader в объекте XMLHttpRequest . (Спецификация CORS называет эти заголовки запросов на создание.) Правило не применяется к заголовкам, которые может задавать браузер , например User-Agent, Host или Content-Length.

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

      OPTIONS http://myservice.azurewebsites.net/api/test HTTP/1.1 Accept: */* Origin: http://myclient.azurewebsites.net Access-Control-Request-Method: PUT Access-Control-Request-Headers: accept, x-my-custom-header Accept-Encoding: gzip, deflate User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; WOW64; Trident/6.0) Host: myservice.azurewebsites.net Content-Length: 0 

      В предварительном запросе используется метод HTTP OPTIONS. Он включает два специальных заголовка:

      • Access-Control-Request-Method: метод HTTP, который будет использоваться для фактического запроса.
      • Access-Control-Request-Headers: список заголовков запросов, заданных приложением для фактического запроса. (Опять же, это не включает заголовки, которые задается браузером.)

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

      HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache Content-Length: 0 Access-Control-Allow-Origin: http://myclient.azurewebsites.net Access-Control-Allow-Headers: x-my-custom-header Access-Control-Allow-Methods: PUT Date: Wed, 05 Jun 2013 06:33:22 GMT 

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

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

      Чтобы разрешить приложению ASP.NET получать и обрабатывать запросы OPTION, добавьте следующую конфигурацию в файл web.config приложения в разделе :

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

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

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

      За действие

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

      public class ItemsController : ApiController < public HttpResponseMessage GetAll() < . >[EnableCors(origins: "http://www.example.com", headers: "*", methods: "*")] public HttpResponseMessage GetItem(int id) < . >public HttpResponseMessage Post() < . >public HttpResponseMessage PutItem(int id) < . >> 

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

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

      [EnableCors(origins: "http://www.example.com", headers: "*", methods: "*")] public class ItemsController : ApiController < public HttpResponseMessage GetAll() < . >public HttpResponseMessage GetItem(int id) < . >public HttpResponseMessage Post() < . >[DisableCors] public HttpResponseMessage PutItem(int id) < . >> 

      Глобально

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

      public static class WebApiConfig < public static void Register(HttpConfiguration config) < var cors = new EnableCorsAttribute("www.example.com", "*", "*"); config.EnableCors(cors); // . >> 

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

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

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

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

      [EnableCors(origins: "http://www.contoso.com,http://www.example.com", headers: "*", methods: "*")] 

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

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

      // Allow CORS for all origins. (Caution!) [EnableCors(origins: "*", headers: "*", methods: "*")] 

      Настройка разрешенных методов HTTP

      Параметр methods атрибута [EnableCors] указывает, каким методам HTTP разрешен доступ к ресурсу. Чтобы разрешить все методы, используйте подстановочное значение «*». В следующем примере разрешены только запросы GET и POST.

      [EnableCors(origins: "http://www.example.com", headers: "*", methods: "get,post")] public class TestController : ApiController < public HttpResponseMessage Get() < . >public HttpResponseMessage Post() < . >public HttpResponseMessage Put() < . >> 

      Настройка разрешенных заголовков запросов

      В этой статье ранее было описано, как предварительный запрос может включать заголовок Access-Control-Request-Headers, перечисляя заголовки HTTP, заданные приложением (так называемые «заголовки запросов автора»). Параметр headers атрибута [EnableCors] указывает, какие заголовки запросов автора разрешены. Чтобы разрешить любые заголовки, задайте для заголовков значение «*». Чтобы разрешить определенные заголовки, задайте для заголовков разделенный запятыми список разрешенных заголовков:

      [EnableCors(origins: "http://example.com", headers: "accept,content-type,origin,x-my-header", methods: "*")] 

      Однако браузеры не совсем согласованы в том, как они задают Access-Control-Request-Headers. Например, в настоящее время Chrome включает «origin». FireFox не включает стандартные заголовки, такие как «Accept», даже если приложение задает их в скрипте.

      Если для заголовков задано значение, отличное от «*», необходимо включить по крайней мере «accept», «content-type» и «origin» и все пользовательские заголовки, которые вы хотите поддерживать.

      Настройка разрешенных заголовков ответов

      По умолчанию браузер не предоставляет приложению все заголовки ответов. Заголовки ответов, доступные по умолчанию:

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

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

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

      [EnableCors(origins: "*", headers: "*", methods: "*", exposedHeaders: "X-Custom-Header")] public class TestController : ApiController < public HttpResponseMessage Get() < var resp = new HttpResponseMessage() < Content = new StringContent("GET: Test message") >; resp.Headers.Add("X-Custom-Header", "hello"); return resp; > > 

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

      Учетные данные требуют специальной обработки в запросе CORS. По умолчанию браузер не отправляет учетные данные с запросом из разных источников. Учетные данные включают файлы cookie, а также схемы проверки подлинности HTTP. Чтобы отправить учетные данные с запросом независимо от источника, клиент должен задать для XMLHttpRequest.withCredentials значение true.

      Использование XMLHttpRequest напрямую:

      var xhr = new XMLHttpRequest(); xhr.open('get', 'http://www.example.com/api/test'); xhr.withCredentials = true; 
      $.ajax(< type: 'get', url: 'http://www.example.com/api/test', xhrFields:

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

      [EnableCors(origins: "http://myclient.azurewebsites.net", headers: "*", methods: "*", SupportsCredentials = true)] 

      Если это свойство имеет значение true, HTTP-ответ будет содержать заголовок Access-Control-Allow-Credentials. Этот заголовок сообщает браузеру, что сервер разрешает учетные данные для запроса независимо от источника.

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

      Будьте внимательны при установке параметра SupportsCredentials в значение true, так как это означает, что веб-сайт в другом домене может отправлять учетные данные пользователя, выполнившего вход, в веб-API от имени пользователя, без уведомления пользователя. В спецификации CORS также указано, что задание для источников значения "*" недопустимо, если свойство SupportsCredentials имеет значение true.

      Настраиваемые поставщики политик CORS

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

      [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false)] public class MyCorsPolicyAttribute : Attribute, ICorsPolicyProvider < private CorsPolicy _policy; public MyCorsPolicyAttribute() < // Create a CORS policy. _policy = new CorsPolicy < AllowAnyMethod = true, AllowAnyHeader = true >; // Add allowed origins. _policy.Origins.Add("http://myclient.azurewebsites.net"); _policy.Origins.Add("http://www.contoso.com"); > public Task GetCorsPolicyAsync(HttpRequestMessage request) < return Task.FromResult(_policy); >> 

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

      [MyCorsPolicy] public class TestController : ApiController < .. // 

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

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

      public class CorsPolicyFactory : ICorsPolicyProviderFactory < ICorsPolicyProvider _provider = new MyCorsPolicyProvider(); public ICorsPolicyProvider GetCorsPolicyProvider(HttpRequestMessage request) < return _provider; >> 

      Чтобы задать ICorsPolicyProviderFactory, вызовите метод расширения SetCorsPolicyProviderFactory при запуске следующим образом:

      public static class WebApiConfig < public static void Register(HttpConfiguration config) < config.SetCorsPolicyProviderFactory(new CorsPolicyFactory()); config.EnableCors(); // . >> 

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

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

      Обратная связь

      Были ли сведения на этой странице полезными?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *