Как отключить cors в chrome
Перейти к содержимому

Как отключить cors в chrome

  • автор:

Несколько советов по работе с CORS для начинающих разработчиков

В этой статье мы с вами разберемся, что такое CORS, CORS-ошибки и из-за чего мы можем с ними сталкиваться. Я также продемонстрирую возможные решения и объясню, что такое предварительные (preflight) запросы, CORS-заголовки и в чем заключается их важность при обмене данными между сторонами. Эта статья рассчитана на тех, у кого уже есть базовые познания в области веб-разработки и некоторый опыт с протоколом HTTP. Я старался писать статью так, чтобы она была понятна и новичкам, будучи наполненной знаниями, но при этом стараясь избегать слишком большого количества технических нюансов, не связанных с темой CORS. Если вы заметите какие-либо ошибки или у вас будут предложения, не стесняйтесь писать мне. В некоторых местах я нарочно делал упрощения, говоря “служба”, подразумевая “сервер”, и наоборот.

Что такое CORS?

Cross-Origin Resource Sharing (CORS или “совместное использование ресурсов различными источниками”) — это контролируемый и применяемый в принудительном порядке клиентом (браузером) механизм обеспечения безопасности на основе HTTP. Он позволяет службе (API) указывать любой источник (origin), помимо себя, из которого клиент может запрашивать ресурсы. Он был разработан в соответствии с same-origin policy (SOP или “политика одинакового источника”), которая ограничивает взаимодействие сайта (HTML-документа или JS-скрипта), загруженного из одного источника, с ресурсом из другого источника. CORS используется для явного разрешения определенных cross-origin запросов и отклонения всех остальных.

В основном CORS реализуют веб-браузеры, но как вариант его также можно использовать в API-клиентах. Он присутствует во всех популярных браузерах, таких как Google Chrome, Firefox, Opera и Safari. Этот стандарт был принят в качестве рекомендации W3C в январе 2014 года. Исходя из этого, можно смело предполагать, что он реализован во всех доступных в настоящее время браузерах, которые не были перечислены выше.

Как это работает?

Все начинается на стороне клиента, еще до отправки основного запроса. Клиент отправляет в службу с ресурсами предварительный (preflight) CORS-запрос с определенными параметрами в заголовках HTTP (CORS-заголовках, если быть точнее). Служба отвечает, используя те же заголовки с другими или такими же значениями. На основе ответа на предварительный CORS-запрос клиент решает, может ли он отправить основной запрос к службе. Браузер (клиент) выдаст ошибку, если ответ не соответствует требованиям предварительной проверки CORS.

Предварительные CORS-запросы отправляются независимо от используемых для отправки запросов из браузера библиотек или фреймворков. Поэтому вам не нужно соответствовать требованиям CORS, когда вы работе с API из вашего серверного приложения.

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

Что такое предварительная проверка CORS?

Когда браузер отправляет запрос на сервер, он сначала отправляет Options HTTP-запрос. Это и есть предварительным CORS-запрос. Затем сервер отвечает списком разрешенных методов и заголовков. Если браузеру разрешено сделать фактический запрос, то тогда он незамедлительно отправит его. Если нет, он покажет пользователю ошибку и не выполнит основной запрос.

CORS-заголовки

CORS-заголовки — это обычные заголовки HTTP, которые используются для контроля политики CORS. Они используются, когда браузер отправляет предварительный CORS-запрос на сервер, на который сервер отвечает следующими заголовками:

  • Access-Control-Allow-Origin указывает, какой источник может получать ресурсы. Вы можете указать один или несколько источников через запятую, например: https://foo.io,http://bar.io .
  • Access-Control-Allow-Methods указывает, какие HTTP-методы разрешены. Вы можете указать один или несколько HTTP-методов через запятую, например: GET,PUT,POST .
  • Access-Control-Allow-Headers указывает, какие заголовки запросов разрешены. Вы можете указать один или несколько заголовков через запятую, например: Authorization,X-My-Token .
  • Access-Control-Allow-Credentials указывает, разрешена ли отправка файлов cookie. По умолчанию: false .
  • Access-Control-Max-Age указывает в секундах, как долго должен кэшироваться результат запроса. По умолчанию: 0.

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

Полный список CORS-заголовков вы можете найти здесь.

Почему запрос может быть заблокирован политикой CORS?

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

Access to XMLHttpRequest at 'http://localhost:8080/' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Приведенная выше CORS-ошибка уведомляет пользователя о том, что браузер не может получить доступ к ресурсу ( https://localhost:8080 ) из источника ( https://localhost:3000 ), поскольку сервер его не одобрил. Это произошло из-за того, что сервер не ответил заголовком Access-Control-Allow-Origin с этим источником или символом * в ответе на предварительный CORS-запрос.

Запрос может быть заблокирован политикой CORS не только из-за невалидного источника, но и из-за неразрешенных заголовка HTTP, HTTP-метода или заголовка Cookie.

Как исправить CORS-ошибку?

Фундаментальная идея “исправления CORS” заключается в том, чтобы отвечать на OPTIONS запросы, отправленные от клиента, корректными заголовками. Есть много способов начать отвечать корректными CORS. Вы можете использовать прокси-сервер или какое-нибудь middleware на своем сервере.

Помните, что заголовки Access-Control-* кэшируются в браузере в соответствии со значением, установленным в заголовке Access-Control-Max-Age . Поэтому перед тестированием изменений вам обязательно нужно чистить кэш. Вы также можете отключить кэширование в своем браузере.

1. Настройка вашего сервера

По умолчанию, если вы являетесь владельцем сервера, вам необходимо настроить на своем сервере CORS-ответы, и это единственный способ правильно решить проблему. Вы можете добиться этого несколькими способами из нескольких слоев вашего приложения. Самый распространенный способ — использовать обратный прокси-сервер (reverse-proxy), API-шлюз или любой другой сервис маршрутизации, который позволяет добавлять заголовки к ответам. Для этого можно использовать множество сервисов, и вот некоторые из них: HAProxy, Linkerd, Istio, Kong, nginx, Apache, Traefik. Если ваша инфраструктура содержит только приложение без каких-либо дополнительных слоев, то вы можете добавить поддержку CORS в код самого приложения.

Вот несколько популярных примеров активации CORS:

  • Apache: отредактируйте файл .htaccess
  • Nginx: отредактируйте файл конфигурации,
  • Traefik: используйте middleware,
  • Spring Boot: используйте аннотацию @EnableCORS,
  • ExpressJS: используйте app.use(cors()),
  • NextJS: используйте реквест-хелперы.

Здесь вы можете найти больше примеров активации CORS для разных фреймворков и языков: enable-cors.org.

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

2. Установка расширения для браузера

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

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

Вы можете найти расширения в Google Web Store или в библиотеке дополнений Mozilla. В некоторых случаях дефолтной конфигурации расширения может быть недостаточно; убедитесь, что установленное расширение корректно настроено. Вам также следует быть в курсе, что если держать подобное расширение включенным постоянно, то это может вызвать проблемы с некоторыми сайтами. Их рекомендуется использовать только в целях разработки.

3. Отключение CORS-проверок в браузере

Вы можете полностью отключить CORS-проверки в своем браузере. Чтобы отключить CORS-проверки в Google Chrome, нужно закрыть браузер и запустить его с флагами —disable-web-security и —user-data-dir . После запуска Google Chrome не будет отправлять предварительные CORS-запросы и не будет проверять CORS-заголовки.

# Windows chrome.exe --user-data-dir="C://chrome-dev-disabled-security" --disable-web-security --disable-site-isolation-trials # macOS open /Applications/Google\ Chrome.app --args --user-data-dir="/var/tmp/chrome-dev-disabled-security" --disable-web-security --disable-site-isolation-trials # Linux google-chrome --user-data-dir="~/chrome-dev-disabled-security" --disable-web-security --disable-site-isolation-trials

Все команды, приведенные выше, запускают Google Chrome в изолированной безопасной среде. Они не затронут ваш основной профиль Chrome.

4. Настройка прокси-сервера

Если вы ищете решение, которое не требует от вас изменения настроек браузера, вам следует обратить внимание на прокси-сервера. Эта опция поможет вам избавиться от CORS-ошибок, ничего не меняя в самом браузере. Идея подхода заключается в том, чтобы отправлять все запросы на ваш сервер, который затем перенаправит запрос реальной службе, которую вы хотите использовать. Вы можете создать прокси-сервер самостоятельно с помощью языка и платформы по вашему предпочтению. Вам потребуется настроить CORS и реализовать функционал передачи полученных запросов в другую службу.

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

Ниже приведен список CORS сервисов с открытым исходным кодом, которые вы можете найти на просторах интернета:

  • https://github.com/Freeboard/thingproxy
  • https://github.com/bulletmark/corsproxy
  • https://github.com/Rob—W/cors-anywhere

Перед использованием любого из этих сервисов обязательно проверьте код самой последний версии версии.

Как протестировать CORS?

Использование браузера для проверки конфигурации CORS может оказаться на удивление утомительной задачей. В качестве альтернативы вы можете использовать такие инструменты, как CORS Tester, test-cors.org или, если вас не страшит командная строка, вы можете использовать curl для проверки конфигурации CORS.

curl -v -X OPTIONS https://simplelocalize.io/api/v1/translations

Остерегайтесь ложных CORS-ошибок

В некоторых случаях, когда сервис находится за дополнительным слоем защиты ограничителя частоты запросов, балансировщика нагрузки или сервера авторизации, вы можете получить ложную CORS-ошибку. Заблокированные или отклоненные сервером запросы должны отвечать статус кодами ошибки. Например:

  • 401 unauthorized,
  • 403 forbidden,
  • 429 too many requests,
  • 500 internal server error,
  • любые, кроме 2XX или 3XX.

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

Заключение

В этой статье я постарался объяснить, что такое CORS и каковы наиболее распространенные проблемы с ним. Я предложил четыре способа избавиться от проблемы с CORS и объяснил преимущества и недостатки каждого из них. Я также объяснил, как правильно настроить CORS-ответы и как их протестировать. Более того, я показал самые распространенные проблемы, с которыми вы можете столкнуться при распознавании ложных CORS-ошибок. Я постарался изложить все максимально простым языком и избежать мудреных технических подробностей. Cпасибо за внимание!

Полезные ссылки

  • https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors
  • https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
  • https://enable-cors.org/
  • https://stackoverflow.com/a/42024918/1133169

Материал подготовлен в преддверии старта онлайн-курса «JavaScript Developer. Professional». Недавно прошел открытый урок на тему «CSS-in-JS. Удобный способ управлять стилями», на котором рассмотрели Styled components, Linaria, Astroturf и другие инструменты упрощения работы со стилями. Посмотреть запись можно по ссылке.

What is CORS?

What is CORS?

Cross-Origin Resource Sharing (CORS) is an HTTP-based security mechanism controlled and enforced by the client (web browser). It allows a service (API) to indicate any origin other than its own from which the client can request resources. It has been designed in response to the same-origin policy (SOP) that restricts how a website (HTML document or JS script) loaded by one origin can interact with a resource from another origin. CORS is used to explicitly allow some cross-origin requests while rejecting others.

CORS is implemented primarily in web browsers, but it can also be used in API clients as an option. It’s present in all popular web browsers like Google Chrome, Firefox, Opera, and Safari. The standard has been accepted as a W3C Recommendation in January 2014. Based on that, we can assume that it is implemented in all currently available and other than listed web browsers.

How does it work?

Everything starts on the client side, before sending the main request. The client sends a CORS preflight request to a service for resources with parameters in HTTP headers (CORS headers). The service responses using the same headers with different or the same values. The client decides, based on a CORS preflight response, if he can or cannot send the main request to the service. The web browser (client) will throw an error if the response does not meet the requirements of CORS preflight.

CORS preflight requests are sent regardless of the used libraries or frameworks to send requests from web browser. That’s why you won’t need to conform CORS requirements when working with API from your backend application.

CORS is not going to prevent users from requesting or downloading resources. You can still make a successful request for a resource using apps like curl, Insomnia, or Postman. CORS is only going to prevent the browser from accessing the resource if the CORS policy does not allow it.

What is a CORS preflight?

When a browser sends a request to a server, it first sends an HTTP Options request. This is called a CORS preflight request. The server then responds with a list of allowed methods and headers. If the browser is allowed to make the actual request, it sends the actual request. If not, it shows an error and does not continue to send the main request.

CORS preflight: Server-Client Requests Scheme

CORS Headers

CORS headers are regular HTTP headers that are used to control the CORS policy. They are used in requests where the browser sends a CORS preflight request to the server, and the server responses with:

  • Access-Control-Allow-Origin indicates what origin can fetch resources. Use one or more origins, e.g.: https://foo.io,http://bar.io .
  • Access-Control-Allow-Methods indicates what HTTP methods are allowed. Use one or more comma HTTP methods, e.g.: GET,PUT,POST .
  • Access-Control-Allow-Headers indicates what request headers are allowed. Use one or more headers, e.g.: Authorization,X-My-Token .
  • Access-Control-Allow-Credentials indicates if sending cookies is allowed. Default: false .
  • Access-Control-Max-Age — indicates how long the request result should be cached, in seconds. Default: 0 .

If you decide to use Access-Control-Allow-Credentials=true , then you need to be aware of the fact you cannot use wildcards * in Access-Control-Allow-* headers. It’s required to explicitly list all allowed origins, methods, and headers.

cors request and response headers

Why is request blocked by CORS policy?

If you are a web developer, you have probably already seen or heard about CORS errors, and you have googled it many times to find the solution. The most common problem is that the browser blocks the request because of CORS policy. The browser will throw an error and show a log in the console:

Access to XMLHttpRequest at 'http://localhost:8080/' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. 

The CORS error above notifies a user that the browser couldn’t access a resource ( https://localhost:8080 ) from an origin ( https://localhost:3000 ) because the server didn’t allow it. It happened because the server didn’t respond with Access-Control-Allow-Origin header with the origin or with a wildcard * in the CORS preflight response.

A request may be blocked by CORS policy not only because of the incorrect origin, but also incorrect HTTP header, HTTP method or Cookie header.

How to fix CORS error?

The fundamental idea of «fixing CORS» is to respond to «OPTIONS» requests sent from a client with proper headers. There are many ways to start responding with the proper CORS. You can use a proxy server, or you can use middleware in your server.

Response to preflight request doesn't pass access control check

Remember that Access-Control-* headers are cached in a web browser according to the value set in Access-Control-Max-Age header. Please make sure that you clear the cache before testing the changes. You can also disable caching in your browser .

1. Configure your server

By default, if you are a server owner, you need to configure CORS responses in your server and this is the only way to address the issue properly. You can achieve this in multiple ways and on multiple layers of your app. The most common way is to use reverse-proxy, API gateway, or any other routing service that offers to add headers to the responses. There are many services that you can use to do this, some of them are: HAProxy, Linkerd, Istio, Kong, nginx, Apache, Traefik. If your infrastructure contains only an application without any additional layers, then you can simply add CORS support in the application code.

successful CORS preflight requests in Firefox Developer console

Here are some popular examples of enabling CORS:

  • Apache: modify .htaccess file,
  • Nginx: modify configuration file,
  • Traefik: use middlewares,
  • Spring Boot: use @EnableCORS annotation,
  • ExpressJS: use app.use(cors()) ,
  • NextJS: use request helpers.

Here you can find more examples of enabling CORS in different frameworks and languages: enable-cors.org.

If you cannot enable CORS in the service, but you still want to make request to it, then you need to use one of the following solutions described below.

2. Install a browser extension

Using a browser extension might be a quick and easy way to solve your problems with CORS in your developer environment. The biggest advantage of using a browser extension is that you don’t need to change your code or configuration. On the other hand, you need to install an extension on every web browser that you use for testing your web application.

Use browser extension to overcome CORS error

Browser extensions alter incoming preflight request by adding the necessary headers to trick the browser. It’s a handy solution to work locally with the production API that accepts requests only from the production domain.

You can find extensions in Google Web Store or in Mozilla Add-ons Library. In some cases, the default extension configuration might not be enough; make sure that the installed extension is configured properly. You should also be aware of that leaving the extension turned on indefinitely may cause problems on some websites. It’s recommended to use them only for development purposes.

3. Disable browser CORS checks

You can disable CORS checks in your browser completely. To disable CORS checks in Google Chrome, you need to close the browser and start it with the —disable-web-security and —user-data-dir flags. By doing that, Google Chrome will not send CORS preflight requests and will not validate CORS headers.

# Windows chrome.exe --user-data-dir="C://chrome-dev-disabled-security" --disable-web-security --disable-site-isolation-trials # macOS open /Applications/Google\ Chrome.app --args --user-data-dir="/var/tmp/chrome-dev-disabled-security" --disable-web-security --disable-site-isolation-trials # Linux google-chrome --user-data-dir="~/chrome-dev-disabled-security" --disable-web-security --disable-site-isolation-trials 

All of those commands above start Google Chrome in an isolated sandbox. They will not affect your main Chrome profile.

Disable security in Google Chrome to overcome CORS error

4. Set up a proxy server

If you are looking for a solution that doesn’t require you to change the browser settings, then you should look at the proxy server solution. This option helps you to overcome CORS errors without changing anything in the browser itself. The idea of using a proxy server is to send all requests to your server, and then the server will send the request to the actual service you want to use. You can build a proxy server on your own in a language and framework of your choice. You will need to configure CORS and implement a functionality to pass requests received requests to another service.

Use proxy server to overcome CORS error

Proxy server is a good solution if you don’t have access to the service you intend to use. There are ready to use and open-source proxy server services, but you should always ensure that they are not trying to intercept your requests with authorization headers and pass them to any 3rd party service. Such security breaches could be catastrophic failure for you and potential users of the service.

List of open-source CORS services that you can find on the internet:

  • https://github.com/Freeboard/thingproxy
  • https://github.com/bulletmark/corsproxy
  • https://github.com/Rob—W/cors-anywhere

Please review the code of the newest version before using any of those services.

How to test CORS?

Using a browser to test your CORS configuration might be a tedious task. You can use a tool like CORS Tester, test-cors.org, or, if you are familiar with the command line, you can use curl to test your CORS configuration.

curl -v -X OPTIONS https://simplelocalize.io/api/v1/translations 

free open-source web-based CORS tester

Beware of false CORS errors

In some cases, when a service is behind an additional layer with rate-limiter, load balancer or authorization server, you can get a false CORS error. Blocked or rejected requests by a server should respond with error status codes. E.g.

  • 401 unauthorized,
  • 403 forbidden,
  • 429 too many requests,
  • 500 internal server error,
  • any other than 2XX or 3XX.

You may see that the request is blocked due to failed preflight request, but in fact, a service just rejects it. You should always check the status code and response body of the response to avoid unnecessary debugging. The browser properly alerts you when a CORS preflight request fails, but the reason for the failure is not necessarily connected to the CORS configuration.

Conclusion

In this article, I tried to explain what CORS is, and what are the most common problems with it. I suggested 4 ways to fix CORS issues and explained the advantages and disadvantages of each one. I also explained how to configure CORS responses properly and how to test them. Moreover, I showed what are the most common issues with recognizing false CORS errors. I tried to put everything in simple terms and avoid technical nuances. If you have any questions, doubts, or suggestions, please do not hesitate to contact me.

Resources

  • https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors
  • https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
  • https://enable-cors.org/
  • https://stackoverflow.com/a/42024918/1133169

CORS и странное поведение в Google Chrome

Во всех браузерах все это прекрасно работает: Opera , Firefox, Yandex, Edge и даже Сафари.
Кроме Google Chrome, там я получаю ошибку Access to XMLHttpRequest at ‘. ‘ from origin ‘. ‘ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
Вроде как нет заголовка ‘Access-Control-Allow-Origin’, но если я сделаю запрос из другого браузера, я там этот заголовок увижу, так что очевидно проблема в Google Chrome

P.S. Заменить ‘*’ на конкретный домен пробовал — не помогло

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 = 'Arun'; function callOtherDomain() if(invocation)  invocation.open('POST', url, true); invocation.setRequestHeader('X-PINGOTHER', 'pingpong'); invocation.setRequestHeader('Content-Type', 'application/xml'); invocation.onreadystatechange = handler; invocation.send(body); > > . . 

      В примере выше, 3 строка создаёт XML тело, чтобы отправить POST запросом на строке 8. Также, на строке 9, «кастомизированный» (не стандартный) заголовок HTTP запроса установлен ( X-PINGOTHER: pingpong ). Такие заголовки не являются частью протокола HTTP/1.1, но, как правило, полезны для веб-приложений. Так как запрос использует Content-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 Arun 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]

      Строки 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 изначально требовал такого поведения, но впоследствии был изменён, чтобы больше не требовать его. Однако большинство браузеров ещё не реализовали это изменение и все ещё демонстрируют поведение, которое требовалось изначально.

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

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

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

      1. Сделайте простой запрос (en-US) для определения (используя Response.url (en-US) для Fetch API, или XHR.responseURL, чтобы определить, на каком URL завершится настоящий предварительный запрос).
      2. Сделайте другой запрос («настоящий» запрос), используя 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-origin

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

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

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