Разкрийте тайните на CORS (Споделяне на ресурси между различни източници) и научете как сигурно да активирате заявки между домейни във вашите уеб приложения. Това ръководство обхваща всичко от основите до напреднали конфигурации, осигурявайки безпроблемна и сигурна комуникация.
Демистифициране на CORS: Цялостно ръководство за споделяне на ресурси между различни източници
В днешния взаимосвързан уеб, приложенията често трябва да достъпват ресурси от различни източници. Тук се намесва Споделянето на ресурси между различни източници (CORS). CORS е ключов механизъм за сигурност, който управлява как уеб браузърите обработват заявки от един източник (домейн, протокол и порт) към друг. Разбирането на CORS е от съществено значение за всеки уеб разработчик, за да създава сигурни и функционални уеб приложения.
Какво е Политиката за същия източник?
Преди да се потопим в CORS, е важно да разберем Политиката за същия източник (SOP). SOP е основен механизъм за сигурност, внедрен в уеб браузърите. Целта му е да предотврати достъпа на злонамерени скриптове от един уебсайт до чувствителни данни на друг. Един източник се дефинира от комбинацията на протокол (напр. HTTP или HTTPS), домейн (напр. example.com) и номер на порт (напр. 80 или 443). Два URL адреса се считат за имащи същия източник, ако споделят един и същ протокол, домейн и порт.
Пример:
http://example.com/app1
иhttp://example.com/app2
- Същият източник (същият протокол, домейн и порт)https://example.com/app1
иhttp://example.com/app1
- Различен източник (различен протокол)http://example.com:8080/app1
иhttp://example.com/app1
- Различен източник (различен порт)http://sub.example.com/app1
иhttp://example.com/app1
- Различен източник (различен поддомейн – счита се за различен домейн)
SOP ограничава достъпа на скриптове до ресурси от различен източник, освен ако не са въведени специфични мерки, като CORS, които да го позволят.
Защо е необходим CORS?
Въпреки че Политиката за същия източник е жизненоважна за сигурността, тя може да бъде и ограничаваща. Много съвременни уеб приложения разчитат на извличането на данни от различни сървъри, като например API или мрежи за доставка на съдържание (CDN). CORS предоставя контролиран начин за облекчаване на SOP и позволяване на легитимни заявки от различни източници, като същевременно поддържа сигурността.
Разгледайте сценарий, при който уеб приложение, хоствано на http://example.com
, трябва да извлече данни от API сървър, хостван на http://api.example.net
. Без CORS браузърът би блокирал тази заявка поради SOP. CORS позволява на API сървъра изрично да посочи кои източници имат право да достъпват неговите ресурси, което позволява на уеб приложението да функционира правилно.
Как работи CORS: Основите
CORS работи чрез поредица от HTTP хедъри, обменяни между клиента (браузъра) и сървъра. Сървърът използва тези хедъри, за да информира браузъра дали му е позволено да достъпи заявения ресурс. Ключовият HTTP хедър е Access-Control-Allow-Origin
.
Сценарий 1: Проста заявка
"Проста заявка" е GET, HEAD или POST заявка, която отговаря на специфични критерии (напр. хедърът Content-Type
е един от application/x-www-form-urlencoded
, multipart/form-data
или text/plain
). В този случай браузърът изпраща заявката директно до сървъра, а сървърът отговаря с хедъра Access-Control-Allow-Origin
.
Клиентска заявка (от http://example.com):
GET /data HTTP/1.1
Host: api.example.net
Origin: http://example.com
Сървърен отговор (от http://api.example.net):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Content-Type: application/json
{
"data": "Някакви данни от сървъра"
}
В този пример сървърът отговаря с Access-Control-Allow-Origin: http://example.com
, което показва, че заявките от http://example.com
са разрешени. Ако източникът в заявката не съответства на стойността в хедъра Access-Control-Allow-Origin
(или ако хедърът липсва), браузърът ще блокира отговора и ще попречи на скрипта от страна на клиента да достъпи данните.
Сценарий 2: Предварителна заявка (за сложни заявки)
За по-сложни заявки, като тези, използващи HTTP методи като PUT, DELETE, или тези с персонализирани хедъри, браузърът извършва "предварителна" (preflight) заявка, използвайки HTTP метода OPTIONS. Тази предварителна заявка иска разрешение от сървъра, преди да изпрати действителната заявка. Сървърът отговаря с хедъри, които посочват кои методи, хедъри и източници са разрешени.
Клиентска предварителна заявка (от http://example.com):
OPTIONS /data HTTP/1.1
Host: api.example.net
Origin: http://example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Сървърен отговор (от http://api.example.net):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Methods: GET, PUT, DELETE
Access-Control-Allow-Headers: X-Custom-Header, Content-Type
Access-Control-Max-Age: 3600
Обяснение на хедърите:
Access-Control-Allow-Origin: http://example.com
- Показва, че заявките отhttp://example.com
са разрешени.Access-Control-Allow-Methods: GET, PUT, DELETE
- Посочва разрешените HTTP методи за заявки от различен източник.Access-Control-Allow-Headers: X-Custom-Header, Content-Type
- Изброява разрешените персонализирани хедъри в действителната заявка.Access-Control-Max-Age: 3600
- Посочва продължителността (в секунди), за която отговорът на предварителната заявка може да бъде кеширан от браузъра. Това помага да се намали броят на предварителните заявки.
Ако отговорът на предварителната заявка от сървъра показва, че заявката е разрешена, браузърът продължава с действителната заявка. В противен случай браузърът блокира заявката.
Действителна клиентска заявка (от http://example.com):
PUT /data HTTP/1.1
Host: api.example.net
Origin: http://example.com
X-Custom-Header: some-value
Content-Type: application/json
{
"data": "Някакви данни, които трябва да бъдат актуализирани"
}
Сървърен отговор (от http://api.example.net):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Content-Type: application/json
{
"status": "Данните са актуализирани успешно"
}
Често срещани CORS хедъри
Ето разбивка на ключовите CORS хедъри, които трябва да разбирате:
Access-Control-Allow-Origin
: Този хедър е най-основният. Той посочва източника(ците), които имат право да достъпват ресурса. Възможните стойности включват:- Конкретен източник (напр.
http://example.com
). *
(wildcard): Това позволява заявки от всеки източник. Използвайте с повишено внимание, тъй като може да компрометира сигурността, ако са замесени чувствителни данни. Обикновено трябва да се избягва в продукционна среда.
- Конкретен източник (напр.
Access-Control-Allow-Methods
: Този хедър посочва HTTP методите (напр. GET, POST, PUT, DELETE), които са разрешени за заявки от различен източник. Използва се в отговора на предварителната заявка.Access-Control-Allow-Headers
: Този хедър изброява персонализираните хедъри, които са разрешени в заявки от различен източник. Той също се използва в отговора на предварителната заявка.Access-Control-Allow-Credentials
: Този хедър показва дали сървърът позволява включването на идентификационни данни (напр. бисквитки, хедъри за оторизация) в заявки от различен източник. Трябва да бъде настроен наtrue
, ако трябва да изпращате идентификационни данни. От страна на клиента също трябва да зададетеwithCredentials = true
на обекта XMLHttpRequest.Access-Control-Expose-Headers
: По подразбиране браузърите излагат само ограничен набор от хедъри на отговора (напр.Cache-Control
,Content-Language
,Content-Type
,Expires
,Last-Modified
,Pragma
) на скриптовете от страна на клиента. Ако искате да изложите други хедъри, трябва да ги изброите в хедъраAccess-Control-Expose-Headers
.Access-Control-Max-Age
: Този хедър посочва максималното време (в секунди), за което браузърът може да кешира предварителната заявка. По-голяма стойност намалява броя на предварителните заявки, подобрявайки производителността.
CORS в различни сървърни езици
Внедряването на CORS обикновено включва конфигуриране на вашето сървърно приложение да изпраща съответните CORS хедъри. Ето примери как да направите това в различни езици и рамки:
Node.js с Express
Можете да използвате пакета за междинен софтуер cors
:
const express = require('express');
const cors = require('cors');
const app = express();
// Активиране на CORS за всички източници (ИЗПОЛЗВАЙТЕ С ВНИМАНИЕ В ПРОДУКЦИОННА СРЕДА)
app.use(cors());
// Алтернативно, конфигурирайте CORS за конкретни източници
// app.use(cors({
// origin: 'http://example.com'
// }));
app.get('/data', (req, res) => {
res.json({ message: 'Това е с активиран CORS за всички източници!' });
});
app.listen(3000, () => {
console.log('Сървърът работи на порт 3000');
});
Python с Flask
Можете да използвате разширението Flask-CORS
:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
# Алтернативно, конфигурирайте CORS за конкретни източници
# CORS(app, resources={r"/api/*": {"origins": "http://example.com"}})
@app.route("/data")
def hello():
return {"message": "Това е с активиран CORS за всички източници!"}
if __name__ == '__main__':
app.run(debug=True)
Java със Spring Boot
Можете да конфигурирате CORS във вашето Spring Boot приложение, като използвате анотации или конфигурационни класове:
Използване на анотации:
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin(origins = "http://example.com") // Разрешаване на заявки от http://example.com
public class DataController {
@GetMapping("/data")
public String getData() {
return "Това е с активиран CORS за http://example.com!";
}
}
Използване на конфигурация:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/data")
.allowedOrigins("http://example.com") // Разрешаване на заявки от http://example.com
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*");
}
}
PHP
"Това е с активиран CORS за http://example.com!");
echo json_encode($data);
?>
CORS и съображения за сигурност
Въпреки че CORS позволява заявки от различни източници, е изключително важно да го внедрите сигурно. Ето някои важни съображения:
- Избягвайте използването на
*
заAccess-Control-Allow-Origin
в продукционна среда: Това позволява заявки от всеки източник, което може да бъде риск за сигурността. Вместо това, изрично посочете източниците, които имат право да достъпват вашите ресурси. - Валидирайте хедъра
Origin
от страна на сървъра: Дори ако използвате рамка, която обработва конфигурацията на CORS, е добра практика да валидирате хедъраOrigin
от страна на сървъра, за да се уверите, че заявката идва от очакван източник. - Бъдете внимателни с
Access-Control-Allow-Credentials
: Ако използвате идентификационни данни (напр. бисквитки, хедъри за оторизация), уверете се, че сте задалиAccess-Control-Allow-Credentials: true
от страна на сървъра иwithCredentials = true
от страна на клиента. Все пак, имайте предвид, че използването наAccess-Control-Allow-Origin: *
не е разрешено, когатоAccess-Control-Allow-Credentials
е зададено наtrue
. Трябва изрично да посочите разрешените източници. - Конфигурирайте правилно
Access-Control-Allow-Methods
иAccess-Control-Allow-Headers
: Разрешете само HTTP методите и хедърите, които са необходими за правилното функциониране на вашето приложение. Това помага да се намали повърхността за атака. - Използвайте HTTPS: Винаги използвайте HTTPS за вашите уеб приложения и API, за да защитите данните при пренос.
Отстраняване на проблеми с CORS
Проблемите с CORS могат да бъдат трудни за отстраняване. Ето някои често срещани проблеми и как да ги решите:
- "Липсва хедър 'Access-Control-Allow-Origin' в заявения ресурс": Това е най-честата грешка при CORS. Тя означава, че сървърът не изпраща хедъра
Access-Control-Allow-Origin
в своя отговор. Проверете отново конфигурацията на сървъра си, за да се уверите, че хедърът се изпраща правилно. - "Отговорът на предварителната заявка не преминава проверката за контрол на достъпа: Няма HTTP ok статус": Тази грешка показва, че предварителната заявка е неуспешна. Това може да се случи, ако сървърът не е конфигуриран да обработва OPTIONS заявки или ако хедърите
Access-Control-Allow-Methods
илиAccess-Control-Allow-Headers
не са конфигурирани правилно. - "Стойността на хедъра 'Access-Control-Allow-Origin' в отговора не е равна на източника в заявката": Тази грешка означава, че източникът в заявката не съответства на стойността в хедъра
Access-Control-Allow-Origin
. Уверете се, че сървърът изпраща правилния източник в отговора. - Кеширане от браузъра: Понякога браузърите могат да кешират CORS отговори, което може да доведе до неочаквано поведение. Опитайте да изчистите кеша на браузъра си или да използвате друг браузър, за да видите дали това решава проблема. Можете също да използвате хедъра
Access-Control-Max-Age
, за да контролирате колко дълго браузърът кешира отговора на предварителната заявка.
Инструменти за отстраняване на грешки:
- Инструменти за разработчици в браузъра: Използвайте инструментите за разработчици на браузъра (обикновено достъпни с натискане на F12), за да инспектирате мрежовите заявки и отговори. Търсете хедъри, свързани с CORS, и съобщения за грешки.
- Онлайн инструменти за проверка на CORS: Има онлайн инструменти, които могат да ви помогнат да тествате вашата CORS конфигурация. Тези инструменти изпращат заявка до вашия сървър и анализират хедърите на отговора, за да идентифицират потенциални проблеми.
Напреднали сценарии с CORS
Въпреки че основните концепции на CORS са сравнително ясни, има някои по-напреднали сценарии, които трябва да се вземат предвид:
- CORS с поддомейни: Ако трябва да разрешите заявки от няколко поддомейна (напр.
app1.example.com
,app2.example.com
), не можете просто да използвате wildcard като*.example.com
в хедъраAccess-Control-Allow-Origin
. Вместо това, ще трябва динамично да генерирате хедъраAccess-Control-Allow-Origin
въз основа на хедъраOrigin
в заявката. Не забравяйте да валидирате източника спрямо бял списък с разрешени поддомейни, за да предотвратите уязвимости в сигурността. - CORS с множество източници: Ако трябва да разрешите заявки от няколко конкретни източника, не можете да посочите няколко източника в хедъра
Access-Control-Allow-Origin
(напр.Access-Control-Allow-Origin: http://example.com, http://another.com
е невалидно). Вместо това, ще трябва динамично да генерирате хедъраAccess-Control-Allow-Origin
въз основа на хедъраOrigin
в заявката. - CORS и CDN: Когато използвате CDN за обслужване на вашето API, трябва да конфигурирате CDN-а да препраща хедъра
Origin
към вашия сървър и да кешира правилно хедъраAccess-Control-Allow-Origin
. Консултирайте се с документацията на вашия доставчик на CDN за конкретни инструкции.
Добри практики при CORS
За да осигурите сигурно и ефективно внедряване на CORS, следвайте тези добри практики:
- Принцип на най-малките привилегии: Разрешете само минималния набор от източници, методи и хедъри, които са необходими за правилното функциониране на вашето приложение.
- Редовно преглеждайте конфигурацията на CORS: С развитието на вашето приложение, редовно преглеждайте конфигурацията на CORS, за да се уверите, че тя все още е подходяща и сигурна.
- Използвайте рамка или библиотека: Възползвайте се от съществуващи рамки или библиотеки, които предоставят вградена поддръжка на CORS. Това може да опрости внедряването и да намали риска от грешки.
- Наблюдавайте за нарушения на CORS: Внедрете наблюдение, за да откривате и реагирате на потенциални нарушения на CORS.
- Бъдете в крак с новостите: Бъдете в крак с най-новите спецификации и препоръки за сигурност на CORS.
Заключение
CORS е критичен механизъм за сигурност, който позволява контролирани заявки от различни източници в уеб приложенията. Разбирането как работи CORS и как да го конфигурирате правилно е от съществено значение за всеки уеб разработчик. Като следвате насоките и добрите практики, очертани в това цялостно ръководство, можете да създавате сигурни и функционални уеб приложения, които безпроблемно взаимодействат с ресурси от различни източници.
Не забравяйте винаги да давате приоритет на сигурността и да избягвате използването на прекалено разрешителни CORS конфигурации. Като внимателно обмисляте последиците за сигурността на вашите CORS настройки, можете да защитите вашите приложения и данни от неоторизиран достъп.
Надяваме се, че това ръководство ви е помогнало да демистифицирате CORS. Приятно кодиране!