Время прочтения
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 и другие инструменты упрощения работы со стилями. Посмотреть запись можно по ссылке.
I have express.js server:
import express from 'express';
import cors from 'cors';
import bodyParser from 'body-parser';
import mongoose from 'mongoose';
import helmet from 'helmet';
import config from './config/config.js';
import authRoutes from './routes/auth.js';
import userRoutes from './routes/user.js';
mongoose.connect(config.mongoUri, { useNewUrlParser: true });
mongoose.connection.on('error', () => {
throw new Error(`unable to connect to database: ${config.mongoUri}`);
});
const port = 9000;
const app = express();
app.use(helmet());
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'POST,GET,LINK');
});
app.use('/', authRoutes);
app.use('/', userRoutes);
app.listen(port, () => console.log(`Example app listening on port ${port}!`));
Cors package install corectly in package.json.
Here is my routes
import express from 'express';
import authCtrl from '../controllers/auth.controller.js';
const router = express.Router();
router.route('/auth/signin').post(authCtrl.signin);
router.route('/auth/signout').get(authCtrl.signout);
export default router;
When i trying to make request from Postman — all is working,
but when try to do in from another server :
const signin = user => {
console.log('user', user);
return fetch('http://localhost:9000/auth/signin/', {
method: 'POST',
headers: {
'Access-Control-Allow-Origin': '*',
Accept: 'application/json',
},
credentials: 'include',
body: JSON.stringify(user),
})
.then(response => {
return response.json();
})
.catch(err => console.log(err));
};
It’s error occur in the console
Access to fetch at ‘http://localhost:9000/auth/signin/’ from origin
‘http://localhost:3000’ has been blocked by CORS policy: Response to preflight request doesn’t pass access control check: The value of the ‘Access-Control-Allow-Origin’ header in the response must not be the wildcard ‘*’ when the request’s credentials mode is ‘include’.
In network i can see OPTIONAL request :
Access-Control-Allow-Headers: access-control-allow-origin
Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
Access-Control-Allow-Origin: *
So how can I fix this problem?
В ходе использования программного интерфейса приложения (API) XMLHttpRequest скриптового языка браузеров JavaScript, обычно в тандеме с технологией AJAX (Asynchronous JavaScript And XML), могут возникать различные ошибки CORS (Cross-origin resource sharing) при попытке доступа к ресурсам другого домена.
Здесь мы условились о том, что:
- src.example.org — это домен, с которого отправляются XMLHttpRequest кросс-доменные запросы
- target.example.com/example.php — это домен и скрипт /example.php, на который XMLHttpRequest кросс-доменные запросы отправляются
Перечисленные ниже CORS ошибки приводятся в том виде, в котором они выдавались в консоль веб-браузера.
https://target.example.com/example.php в данном примере фактически был размещён на сервере страны отличной от Украины и посредством CURL предоставлял доступ к российскому сервису проверки правописания от Яндекса, — как извесно доступ к сервисам Яндекса из Украины был заблокирован большинством Интернет-провайдеров.
При попытке проверить правописание в редакторе выдавалась ошибка: «The spelling service was not found: (https://target.example.com/example.php)«
Причина: отсутствует заголовок CORS ‘Access-Control-Allow-Origin’
«NetworkError: 403 Forbidden — https://target.example.com/example.php»
example.php
Запрос из постороннего источника заблокирован: Политика одного источника запрещает чтение удаленного ресурса на https://target.example.com/example.php. (Причина: отсутствует заголовок CORS ‘Access-Control-Allow-Origin’).
Запрос из постороннего источника заблокирован: Политика одного источника запрещает чтение удаленного ресурса на https://target.example.com/example.php. (Причина: не удалось выполнить запрос CORS).
Решение: отсутствует заголовок CORS ‘Access-Control-Allow-Origin’
CORS для src.example.org должно быть разрешено на стороне сервера принимающего запросы — это можно сделать в .htaccess следующим образом:
<Files ~ "(example)+.php"> Header set Access-Control-Allow-Origin "https://src.example.org" </Files>
Причина: неудача канала CORS preflight
«NetworkError: 403 Forbidden — https://target.example.com/example.php» example.php
Запрос из постороннего источника заблокирован: Политика одного источника запрещает чтение удаленного ресурса на https://target.example.com/example.php. (Причина: неудача канала CORS preflight).
Запрос из постороннего источника заблокирован: Политика одного источника запрещает чтение удаленного ресурса на https://target.example.com/example.php. (Причина: не удалось выполнить запрос CORS).
Решение: неудача канала CORS preflight
Причины здесь могут быть разные, среди которых может быть запрет некоторых ИП на стороне брандмауэра, либо ограничения на методы запроса в том же .htaccess строкой: «RewriteCond %{REQUEST_METHOD} !^(post|get) [NC,OR]
«.
Во-втором случае это может быть зафиксировано в лог-файле ошибок сервера:
xxx.xxx.xx.xxx [07/May/2018:09:55:15 +0300] «OPTIONS /example.php HTTP/1.1» 403 «Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:52.0) Gecko/20100101 Firefox/52.0» «Referer: -«
Примечание:
Нужно помнить, что ИП-адрес в лог-файле сервера принадлежит клиенту/браузеру, а не удалённому серверу src.example.org на страницах которого в браузере клиента был инициирован CORS (кросс-доменный) запрос!
В случае с .htaccess
строку подправим до такого состояния: «RewriteCond %{REQUEST_METHOD} !^(post|get|options) [NC,OR]
«.
Причина: отсутствует токен ‘x-requested-with’ в заголовке CORS ‘Access-Control-Allow-Headers’ из канала CORS preflight
Запрос из постороннего источника заблокирован: Политика одного источника запрещает чтение удаленного ресурса на https://target.example.com/example.php. (Причина: отсутствует токен ‘x-requested-with’ в заголовке CORS ‘Access-Control-Allow-Headers‘ из канала CORS preflight).
Запрос из постороннего источника заблокирован: Политика одного источника запрещает чтение удаленного ресурса на https://target.example.com/example.php. (Причина: не удалось выполнить запрос CORS).
Решение: отсутствует токен ‘x-requested-with’ в заголовке CORS ‘Access-Control-Allow-Headers’ из канала CORS preflight
Посредством .htaccess
добавим заголовок Access-Control-Allow-Headers:
<Files ~ "(example)+.php"> Header set Access-Control-Allow-Origin "https://src.example.org" Header set Access-Control-Allow-Headers: "X-Requested-With" </Files>
Access-Control-Allow-Origin для множества доменов
Заголовок Access-Control-Allow-Origin допускает установку только одного источника, однако при необходимости разрешения CORS для множества источников в .htaccess можно извратится следующим образом:
##### ---+++ BEGIN MOD HEADERS CONFIG +++--- <IfModule mod_headers.c> <Files ~ "(example)+.php"> #Header set crossDomain: true # ## Allow CORS from one domain #Header set Access-Control-Allow-Origin "https://src.example.org" ## Allow CORS from multiple domain SetEnvIf Origin "http(s)?://(www.)?(example.org|src.example.org)$" AccessControlAllowOrigin=$0 Header set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin # ## Origin, X-Requested-With, Content-Type, Accept, X-Auth-Token Header set Access-Control-Allow-Headers: "X-Requested-With" # ## "GET, POST" Header set Access-Control-Allow-Methods "POST" # #Header set Access-Control-Allow-Credentials true #Header set Access-Control-Max-Age 60 </Files> </IfModule> ##### ---+++// END MOD HEADERS CONFIG +++---
Всем привет!
Меня зовут Радик, я 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!
CORS is an abbreviation for Cross-Origin Response Sharing. It is what allows the website on one URL to request data from a different URL, and it frustrates both the frontend and backend devs alike. You might’ve added an image URL only to end up with something like this.
Or, your API fails and shows a CORS error in the console.
This happens because the same-origin policy is part of the browser’s security model which allows websites to request data from APIs of the same URL but blocks those of different URLs. Browsers do this by adding an ORIGIN key in the request.
However, let’s say if the server was on bar.com then the browser will prevent showing this to the client because it had a cross-origin response.
Why is CORS blocked?
It is to prevent cross-site request forgery. Let’s say you log in to facebook.com and your browser stores the authentication token so that in the future you get logged in automatically. And for every request to the origin facebook.com, these auth-token headers will be present. Now imagine a scenario where you click on a pop-up opening badSite.com. They also have the ability to make requests to facebook.com. In this case, the browser will add related cookies and your token will be shared with badSite.com, and your account has been successfully hacked with a cross-site request forgery attack. To prevent this the CORS error was introduced.
How do we solve these issues?
The first method is the quickest, but it is not the right way. It is mostly used during development when you need to start implementing the API quickly and can wait a bit for the final production build. As you might have guessed, we are going to tell the browser to stop caring about these errors. This can be done by installing a chrome extension.
Once installed, click on it and make sure it says on. Once done just refresh your app.
Why is this fix a deceiving one?
As you can see, whatever this extension did was to stop YOUR browser from checking the CORS error. But when you deliver it to your client this won’t work.
Solving CORS error the right way
Now, If you are in control of the server then lucky for you because you actually have some power to solve this. But if not, then you are out of luck.
For example, if you want to solve this on the express.js then all you have to do is use a certain middleware that will handle the origin key.
1 2 3 4 5 6 7 8 9 10 11 12
const express = require('express'); const app = express(); const cors = require('cors'); app.use(cors({ origin: 'https://foo.com' })); app.get('/', (req, res) => { res.send('CORS solved') })
But, for any non-standard HTTP request like PUT, PATCH, DELETE, you’ll have to preflight them. The term preflight is used because it’s like a security check before you board a plane to make sure the passengers (or request) are safe to deploy on the airplane (or server) or not. The neat thing is that the browser automatically knows when to preflight and the server responds accordingly whether these non-standard requests are allowed or not.
And at this point, these requests can happen properly. This sounds inefficient, because your service will have to deal with this at every request but the server has an option to respond with a header called Access-Control-Max-Age:86400 which will keep these details saved for the specified time.
Still facing a CORS error?
Open a network tab in your console.
In the response header look for the Access-Control-Allow-Origin header. If it does not exist then add it as a middleware in the way we discussed above. If it does exist then make sure there is no URL mismatch with the website.
And if all is fine then check whether it is a non-standard HTTP request and you need to allow them.
How to allow from multiple origin domains:
Let’s say in your express app you only want to allow requests from www.example1.com www.example2.com and www.example3.com.
You will do it in the following way with the help of middleware.
1 2 3 4 5 6 7 8
app.use((req, res, next) => { const allowedOrigins = ['www.example1.com', 'www.example2.com', 'www.example3.com']; const origin = req.headers.origin; if (allowedOrigins.includes(origin)) { res.setHeader('Access-Control-Allow-Origin', origin); } return next(); });
Now, let’s look at the Access-Control header family with a bit of detail. You can do various things and put several restrictions with their help.
For example you can allow only certain types of requests in the following way.
res.header('Access-Control-Allow-Methods', 'GET, POST');
This will allow only GET and POST requests.
If you want to fix the headers that can be sent by client then you can do that in the following way.
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
If you want the browser to expose things like cookies/authorization headers, or the TLS client certificates then you can do that in the following way.
res.header('Access-Control-Allow-Credentials', true);
These are some of the popular Access-Control header family members.
Goodbye.
Click to show preference!
Click to show preference!
D0A3FC91-EEC2-4529-BF7D-3B777D79E185 Chat on Discord