Время прочтения
8 мин
Просмотры 12K
В этой статье мы с вами разберемся, что такое 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.
Список всех доступных флагов для Google 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 и другие инструменты упрощения работы со стилями. Посмотреть запись можно по ссылке.
Всем привет!
Меня зовут Радик, я frontend developer компании Creative. И сегодня я хочу поднять тему, которая касается и фронта и бэка, и окружает нас с вами каждый день. Речь пойдёт об ошибках CORS и как их можно обойти.
Уверен, что многим разрабам знакома ситуация, когда ты работаешь над приложением, оно запущено локально, и тебе нужно сделать из него запросы к различным удалённым ресурсам. В этот момент «что-то идёт не так», и ты видишь на своём экране миллион ошибок в консоли браузера. Почему они появляются? Давайте разбираться вместе. В этой статье расскажу о средствах защиты браузера и о том, что он может от вас скрывать в процессе кроссдоменных запросов. Фича: об ошибках будем говорить в картинках 
SOP – Same Origin Policy
Рассмотрим кейс. Мы заходим на какой-то незнакомый сайт, созданный потенциальным злоумышленником. Внешне пока не видим ничего подозрительного, но пока мы находимся на этом сайте, злобный скрипт уже готовит запрос к серверу банка, в котором мы залогинены, и пытается получить наши данные:
Как же браузер пытается нас от этого защитить? Он использует Политику одинакового источника: Same Origin Policy (SOP).
В тех случаях, когда запрос отправляется на ресурс, у которого отличается домен / порт / протокол, – браузер по умолчанию понимает, что он кроссдоменный и применяет политику безопасности:
CORS – Cross Origin Resource Sharing
Что же делать в том случае, когда нам необходимо разрешить для браузера взаимодействие между различными ресурсами?
Браузер должен отправить в запросе заголовок:
**origin: htttps://good-website.com**
Сервер проверит, откуда к нему пришёл запрос, и (если этот домен разрешён) в ответе вернёт заголовок:
**access-control-allow-origin: htttps://good-website.com**
ACAH – Access-Control-Allow-Headers
Браузер может запретить доступ к некоторым заголовкам ответа из кода, ничего не сообщив при этом разработчику.
Так получается, потому что по умолчанию при кроссдоменных запросах браузер разрешает чтение только следующих заголовков ответа:
-
Cache-Control
- Content-Language
- Content-Length
- Content-Type
- Expires
- Last-Modified
- Pragma
Поэтому в network вкладке браузера мы видим абсолютно все интересующие нас заголовки, а из кода JS они будут нам недоступны.
Для того чтобы браузер разрешил доступ к этим заголовкам, в ответе должен быть указан заголовок Access-Control-Allow-Headers.
В нём нужно перечислить заголовки, доступ к которым разрешён браузером:
Специальное значение * позволяет разрешить для использования любые заголовки, но только в том случае, если в изначальном запросе нет cookie или данных аутентификации. В противном случае оно будет рассматриваться как буквальное имя заголовка «*».
Proxy как одно из возможных решений проблемы при локальной разработке
Рассмотрим ещё один кейс. Нам нужно сделать кроссдоменный запрос из приложения, которое развёрнуто локально. Но такой запрос в нужный нам момент не обрабатывается должным образом на сервере. Картинка для понимания.
Как быть? Можно запустить локальный proxy сервер, который будет пересылать данные между нашим приложением и сервером, добавляя необходимые заголовки:
Можно сделать простой proxy сервер на Node.js для решения проблемы с кроссдоменными запросами:
- Для этого переходим в директорию, в которой вы хотите создать прокси сервер
- Инициализируем Node.js проект командой npm init
- Устанавливаем необходимые пакеты командой npm install cors express http-proxy-middleware
- Создаём файл index.js со следующим содержимым:
-
Запускаем proxy сервер командой node index.js
- Теперь мы можем использовать адрес и порт, указанный в proxy сервере в приложении во время разработки.
На этом всё. Мы рассмотрели причины возникновения ошибки CORS и одно из возможных решений при локальной разработке на фронте. Надеюсь, мой материал будет вам полезен. Буду рад продолжить обсуждение темы в комментариях. Всем хорошего дня и поменьше ошибок CORS!
Hello, this is my request:
axios({ method: 'POST', url:${SERVER_ADDRESS}/api/v1/manager/restaurant/${restaurantName}/payment-methods, crossDomain: true, data: { payment_methods: checkedPayments }, }) .then(() => { dispatch(loadPayments(restaurantName)); }).catch((error) => { console.log(error); dispatch(paymentsError()); });
the server is laravel 5, it is responding with:
XMLHttpRequest cannot load http://localhost:8000/api/v1/manager/restaurant/accusamus/payment-methods. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.
Server headers are set with CORS middleware like this:
return $next($request)
->header("Access-Control-Expose-Headers", "Access-Control-*")
->header("Access-Control-Allow-Headers", "Access-Control-*, Origin, X-Requested-With, Content-Type, Accept")
->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS, HEAD')
->header('Access-Control-Allow-Origin', '*')
->header('Allow', 'GET, POST, PUT, DELETE, OPTIONS, HEAD');
Theese are the response headers, which I get when I use postman:
Access-Control-Allow-Headers →Access-Control-, Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Methods →GET, POST, PUT, DELETE, OPTIONS, HEAD
Access-Control-Allow-Origin →
Access-Control-Expose-Headers →Access-Control-*
Allow →GET, POST, PUT, DELETE, OPTIONS, HEAD
Cache-Control →no-cache
Connection →close
Content-Type →text/html; charset=UTF-8
Date →Sat, 03 Dec 2016 10:33:04 GMT
Host →localhost:8000
X-Powered-By →PHP/7.0.13
X-RateLimit-Limit →60
X-RateLimit-Remaining →59
phpdebugbar-id →0ff14bef1824f587d8f278c87ab52544
AXIOS sends preflight which is:
Request URL:http://localhost:8000/api/v1/manager/restaurant/accusamus/payment-methods
Request Method:OPTIONS
Status Code:200 OK
Remote Address:[::1]:8000
Response Headers
view source
Allow:GET,HEAD,POST
Cache-Control:no-cache
Connection:close
Content-Type:text/html; charset=UTF-8
Date:Sat, 03 Dec 2016 10:25:27 GMT
Host:localhost:8000
X-Powered-By:PHP/7.0.13
Request Headers
view source
Accept:/
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:localhost:8000
Origin:http://localhost:3000
Referer:http://localhost:3000/restaurant-profile/payment
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36
Am I doing something wrong? I can’t figure it how to do this. Witch Chrome plugin CORS everything works fine, but this is not the way.
Please help, help is really appreciated, spent hours with this.
Cross-Origin Resource Sharing (
CORS) is a mechanism or a protocol that allows devices on one domain to access resources residing on other domains.
Generally, for security reasons, browsers forbid requests that come in from cross-domain sources. However, there could be cases where you want to overcome this and access cross-domain resources, and CORS makes this possible.
There is another concept known as
Same-Origin Policy (
SOP) which enables resource sharing on similar domains. In this guide, we will discuss the
SOP and how it helps to secure websites. We will also discuss how CORS extends the flexibility and adds pace to the SOP.
Same-Origin Policy (SOP)
The Same-Origin Policy was developed as a security mechanism for browsers to protect resources from malicious attacks. SOP allows resource sharing (data exchange) between two objects with the same origins.
This means that the origin of two websites should be the same if they want to share resources. For two websites to have the same origins, the websites should have the same domain, port number, and protocol type. If any one of these three properties is found different, then the sources are considered different origins.
While SOP is considered a restrictive system, it is highly secured, eliminating potential attacks on websites through cross-domain resources.
SOP offers security to websites but can also be a huddle to interact with third-party websites. Many dynamic websites regularly share a cross-domain resource with trusted websites and subdomains.
With SOP in place, access to cross-origin websites is restricted, and controlled access to resources is possible using Cross-Origin Resource Sharing (CORS).
Cross-Origin Resource Sharing (CORS)
CORS was introduced to provide easy and quick access to subdomains and trusted third parties. CORS enables controlled resource sharing between cross-domain origins as discussed earlier.
The browser and cross-origin website you are trying to access collectively exchange HTTP headers that define trusted web origins and associated properties for access control, as defined by CORS specifications.
CORS offers controlled access to cross-domain websites and hence is well secured. CORS is widely implemented to tackle limitations introduced by SOP. However, if poorly executed, CORS can cause severe security risks. Improper configuration of CORS may present some challenges and errors.
Let us learn more about CORS errors and best practices to avoid them.
Understanding and Fixing CORS Error
CORS is implemented on the server-side; it cannot be reconfigured on the client-side. The CORS behavior, commonly termed as CORS error, is a mechanism to restrict users from accessing shared resources.
This is not an error but a security measure to secure users or the website which you are accessing from a potential security breach.
This breach may occur due to incomplete or improper HTTP headers on the client-side implementation (eg. missing authorization data such as API key).
Best Practices to Avoid CORS Errors
Let’s discuss some of the best practices for avoiding CORS errors by using a Custom Field Extension in Contentstack.
Proxy the API Request While Using External Calls in an Extension
CORS proxy can be a helpful solution to make cross-origin requests. The proxy layer sits between your request and its destination without knowing the request’s origin.
Thus, though the request comes from an unknown source, the CORS proxy makes it seem that it is a request from an allowed location.
To learn how to do this, here is the list of
CORS-Proxy which you can use for your website.
Free Proxies can be great for testing, but relying on a free third-party tool is not advisable for something you will use on the production site. In such cases, a more stable solution is to call the API from a server and make the data available on the client-side.
Use a Serverless Function
A more commonly used solution to resolve CORS error is to use a serverless function. It is an alternate way to proxy your requests, but instead of relying on a free third-party service, you can build your micro-infrastructure to call a web service and feed data to an API endpoint.
Popular serverless functions include AWS Lambda, Azure Functions, and Google Cloud functions. These services allow you to get just enough server space to run a function or two, as you do not need much space to run a function that calls a web service to return some data.
To understand this better, let’s consider a use case:
A user wants to create an extension in Contentstack which will fetch the maps data from the
Google Maps API to get data related to longitude and latitude within your entry.
The user has to follow the steps below:
- Create a custom extension in Contentstack using the UI extension SDK. This extension will make an API call to the Google Maps API to fetch the data in your entry.
The request will fail due to the cross-origin policy set at Google’s server, which will not let you fetch the data, resulting in a CORS error at your client-side. - To solve this problem, you can create an API Gateway URL in AWS with CORS enabled to serve the responses from the Google Maps API with our AWS Lambda function. For example:
exports.handler = async (event) => { try{ return { statusCode: 200, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token', 'Access-Control-Allow-Methods': 'OPTIONS,POST', 'Access-Control-Allow-Credentials': true, 'Access-Control-Allow-Origin': '*', 'X-Requested-With': '*', }, body: JSON stringified object, }; } catch (error) { console.log(error); return { statusCode: 500, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token', 'Access-Control-Allow-Methods': 'OPTIONS,POST', 'Access-Control-Allow-Credentials': true, 'Access-Control-Allow-Origin': '*', 'X-Requested-With': '*', }, body: JSON.stringify({ name: error.name, code: error.code, message: error.message, }), }; } };
- The extension that we have created will make an appropriate call i.e., GET, POST, and so on, to our API Gateway URL & trigger our lambda function.
- The AWS Lambda will then return the maps API response to our client-side. This will fetch the maps data from Google Maps within your entry in Contentstack.
Note: For external hosting of the extension source code, the ‘allow-same-origin’ option will be enabled. Here, the origin refers to the domain where you’ve hosted the extensions. Also, ensure that the response header has the exact origin URL passed in the request header.
For Contentstack-hosted extensions, the iframe’s origin will be null as we don’t enable the ‘allow-same-origin’ flag.
CORS Issue in Frontend Frameworks
The CORS configuration can sometimes be tricky to achieve, and hence developers serve both the backend and frontend under the same domain in production.
To minimize this effort and provide flexibility to work with CORS, React, Nuxt, Express, etc. allow users to replicate the setup in development. This setup is done at the server end, so whenever a cross-origin request is made to the server, we can use a middleware like http-proxy-middleware to proxy requests.
Furthermore, we can also redirect and change the path of the request by using options like pathRewrite.
CORS errors
Совместное использование ресурсов между источниками ( CORS ) — это стандарт, который позволяет серверу ослабить политику одного источника . Это используется для явного разрешения одних запросов из разных источников при отклонении других. Например, если сайт предлагает встраиваемую услугу, может потребоваться ослабить определенные ограничения. Настроить такую конфигурацию CORS не обязательно просто и могут возникнуть некоторые проблемы. На этих страницах мы рассмотрим некоторые распространенные сообщения об ошибках CORS и способы их устранения.
Если конфигурация CORS настроена неправильно, в консоли браузера будет отображаться сообщение об ошибке типа "Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at $somesite" что указывает на то, что запрос был заблокирован из-за нарушения безопасности CORS. правила. Однако это не обязательно может быть ошибкой настройки. Возможно, что запрос на самом деле намеренно запрещен веб-приложением пользователя и удаленной внешней службой. Однако, если конечная точка должна быть доступна, для успешного выполнения потребуется некоторая отладка.
Выявление проблемы
Чтобы понять суть проблемы с конфигурацией CORS,необходимо выяснить,в каком запросе ошибка и почему.Эти шаги могут помочь вам в этом:
- Перейдите на нужный веб-сайт или веб-приложение и откройте Инструменты разработчика .
- Теперь попробуйте воспроизвести неудачную транзакцию и проверьте консоль , если вы видите сообщение об ошибке нарушения CORS. Вероятно, это будет выглядеть так:
Текст сообщения об ошибке будет похож на следующий:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://some-url-here. (Reason: additional information here).
Примечание. По соображениям безопасности подробности о том, что пошло не так с запросом CORS , недоступны для кода JavaScript . Код знает только то, что произошла ошибка. Единственный способ определить, что именно пошло не так, — это посмотреть подробности в консоли браузера.
сообщения об ошибках CORS
See also
- Glossary: CORS
- CORS introduction
- Настройки CORS на стороне сервера
- CORS включенное изображение
- атрибуты настроек CORS
- https://www.test-cors.org — страница для тестирования запросов CORS.
HTTP
-
CORS
Cross-Origin Resource Sharing (CORS)-это механизм,основанный на HTTP-заголовках,который позволяет серверу указывать любое происхождение (домен,схема,порт),отличное от его происхождения.
-
Заголовки ответа HTTP
В этом разделе перечислены заголовки HTTP-ответов,которые серверы возвращают для запросов контроля доступа,определенных спецификацией Cross-Origin Resource Sharing.
-
Errors: CORSAllowOriginNotMatchingOrigin
Происхождение,делающее запрос,не соответствует разрешенному заголовком Access-Control-Allow-Origin.
-
Errors: CORSDidNotSucceed
HTTP-запрос,использующий CORS,завершился неудачей из-за сбоя соединения на уровне сетевого протокола.
В локальной сети между машинами, а также на одной машине в режиме отладки, делаю POST запросы XMLHttpRequest для выгрузки файла на второй сервер.
Со страницы https://xxx
(, где ключи и сертификат самоподписанные (уровня 1). Тестовый сервер Nginx, в продакшене будет другой, но там такие же ошибки.)
на сервер https://upserver:8888
(, где ключи и сертификаты самоподписанные (уровня 2, с использованием собственного центра сертификации, корневых, промежуточных и конечных сертификатов)
На порту 8888 работает Cowboy (Erlang/OTP v.23). Код с заголовками показан ниже.) Пока, там нет авторизации, а кросс-доменные запросы разрешены для всех (*).
Оба домена прописаны в hosts. В продакшене будут прописаны в DNS. Разрешения CORS установлены на обоих серверах, код показан ниже.
При первом открытии index.html на обоих серверах в браузере Chrome получаю ошибку сертификата, но после разрешения ресурса, страница открывается и далее работает. Хотелось бы чтобы она открывалась без этой ошибки и необходимости разрешения.
При загрузке файла на второй сервер в логе браузера (вкладка console) получаю следующие ошибки
Access to XMLHttpRequest at 'https://upserver:8888/upload' from origin 'https://xxx' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
upload.js:73 onreadystatechange Error 0 occurred when trying to upload your file.
upload.js:78 POST https://upserver:8888/upload net::ERR_FAILED
fileUpload @ upload.js:78
(anonymous) @ upload.js:103
upload.js:78 XHR failed loading: POST "https://upserver:8888/upload".
fileUpload @ upload.js:78
(anonymous) @ upload.js:103
Но файл успешно загружается на сервер.
Не могу понять, что ему еще надо, и как исправить эту CORS ошибку?
Код заголовков на upserver:8888
options(Req, Opts) ->
Req1 = cowboy_req:set_resp_header(<<"access-control-allow-methods">>, <<"HEAD, OPTIONS, GET, PUT, POST">>, Req),
Req2 = cowboy_req:set_resp_header(<<"access-control-allow-headers">>, <<"Origin, X-Requested-With, Content-Type,
Accept, x-client-key, x-client-token, x-client-secret">>, Req1),
Req3 = cowboy_req:set_resp_header(<<"access-control-allow-origin">>, <<$*>>, Req2),
{ok, Req3, Opts}.
init(Req, Opts) ->
case cowboy_req:method(Req) of
<<"POST">> ->
{ok, Req1, Opts1} = options(Req, Opts),
{ok, Headers, Req2} = cowboy_req:read_part(Req1),
{ok, Data, Req3} = cowboy_req:read_part_body(Req2),
{file, <<"upfile">>, Filename, ContentType} = cow_multipart:form_data(Headers),
io:format("Received file ~p of content-type ~p as follow:~n~p~n~n", [Filename, ContentType, Data]),
Filepath = filename:join([code:priv_dir("upserver"), "upload", Filename]),
file:write_file(Filepath, Data),
{ok, Req3, Opts1};
_ ->
io:format("Method=~p~n",[cowboy_req:method(Req)]),
options(Req, Opts)
end.
Код запроса на клиенте
function fileUpload(blob){
var filename="test.png";
var file=new File([blob],filename,{type:"image/png"});
var formData = new FormData();
formData.append('upfile', file, filename);
const xhr = new XMLHttpRequest();
xhr.fileinfo = {'filename': filename};
xhr.enctype = "multipart/form-data";
xhr.overrideMimeType('multipart/form-data');
// эта функция работает без ошибок и сообщений
xhr.open("POST", "https://upserver:8888/upload", true);
// Это не помогло, бесполезно, поэтому закоментировано
// xhr.setRequestHeader("Access-Control-Allow-Origin","https://upserver:8888");
// xhr.setRequestHeader("Access-Control-Request-Header","X-Requested-With");
// Это сообщение показано в логе, смотрите лог, Error = xhr.status = 0, вместо 200
xhr.onreadystatechange = function() {
if (xhr.status == 200) {
console.log("onreadystatechange Uploaded!");
} else {
console.log("onreadystatechange Error " + xhr.status + " occurred when trying to upload your file.");
}
};
// здесь выдается сообщение об ошибке CORS
xhr.send(formData);
// В результате, formData успешно передается и правильно сохраняется на сервере, несмотря на все эти ошибки!
}
На стороне первого сервера https://xxx в конфигурации сайта под Nginx прописана следующая конфигурация
server {
listen 443 ssl;
listen [::]:443 ssl;
configuration.
root /var/www/https;
index index.html index.htm index.nginx-debian.html;
server_name xxx;
ssl_certificate /etc/nginx/xxx-list.crt;
ssl_certificate_key /etc/nginx/xxx.key;
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'https://yyy:8888';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' 'https://upserver:8888';
# add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
# add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
}
try_files $uri $uri/ =404;
}
Видно, что кросс-доменные запросы разрешены для второго сервера upserver:8888
Вроде бы, везде всё настроено белее менее правильно, но ошибки мне очень не нравятся.
Хотелось бы разобраться, что не так, и избавиться от ошибок.








