Komplexní průvodce pro pochopení a implementaci Cross-Origin Resource Sharing (CORS) pro bezpečnou komunikaci v JavaScriptu mezi různými doménami.
Implementace zabezpečení Cross-Origin: Osvědčené postupy pro komunikaci v JavaScriptu
V dnešním propojeném světě webu musí JavaScriptové aplikace často interagovat se zdroji z různých původů (domén, protokolů nebo portů). Tuto interakci řídí prohlížečová Same-Origin Policy, klíčový bezpečnostní mechanismus navržený tak, aby zabránil škodlivým skriptům v přístupu k citlivým datům přes hranice domén. Legitimní komunikace mezi různými původy je však často nezbytná. Právě zde přichází na řadu Cross-Origin Resource Sharing (CORS). Tento článek poskytuje komplexní přehled CORS, jeho implementace a osvědčených postupů pro bezpečnou komunikaci mezi různými původy v JavaScriptu.
Pochopení Same-Origin Policy
Same-Origin Policy (SOP) je základní bezpečnostní koncept ve webových prohlížečích. Omezuje skripty běžící na jednom původu v přístupu ke zdrojům z jiného původu. Původ je definován kombinací protokolu (např. HTTP nebo HTTPS), názvu domény (např. example.com) a čísla portu (např. 80 nebo 443). Dvě URL mají stejný původ pouze tehdy, pokud se všechny tři složky přesně shodují.
Například:
http://www.example.comahttp://www.example.com/path: Stejný původhttp://www.example.comahttps://www.example.com: Jiný původ (jiný protokol)http://www.example.comahttp://subdomain.example.com: Jiný původ (jiná doména)http://www.example.com:80ahttp://www.example.com:8080: Jiný původ (jiný port)
SOP je klíčovou obranou proti útokům Cross-Site Scripting (XSS), při kterých mohou škodlivé skripty vložené do webové stránky krást uživatelská data nebo provádět neoprávněné akce jménem uživatele.
Co je Cross-Origin Resource Sharing (CORS)?
CORS je mechanismus, který používá HTTP hlavičky, aby umožnil serverům určit, které původy (domény, schémata nebo porty) mají povolen přístup k jejich zdrojům. V podstatě uvolňuje Same-Origin Policy pro specifické požadavky mezi různými původy, což umožňuje legitimní komunikaci a zároveň chrání před škodlivými útoky.
CORS funguje přidáním nových HTTP hlaviček, které specifikují povolené původy a metody (např. GET, POST, PUT, DELETE), jež jsou povoleny pro požadavky mezi různými původy. Když prohlížeč provede požadavek mezi různými původy, odešle s ním hlavičku Origin. Server odpoví hlavičkou Access-Control-Allow-Origin, která specifikuje povolený původ (původy). Pokud se původ požadavku shoduje s hodnotou v hlavičce Access-Control-Allow-Origin (nebo pokud je hodnota *), prohlížeč umožní JavaScriptovému kódu přístup k odpovědi.
Jak CORS funguje: Detailní vysvětlení
Proces CORS obvykle zahrnuje dva typy požadavků:
- Jednoduché požadavky: Jedná se o požadavky, které splňují specifická kritéria. Pokud požadavek splňuje tyto podmínky, prohlížeč jej odešle přímo.
- Preflight požadavky: Jedná se o složitější požadavky, které vyžadují, aby prohlížeč nejprve odeslal "preflight" požadavek OPTIONS na server, aby zjistil, zda je bezpečné odeslat skutečný požadavek.
1. Jednoduché požadavky
Požadavek je považován za "jednoduchý", pokud splňuje všechny následující podmínky:
- Metoda je
GET,HEADneboPOST. - Pokud je metoda
POST, hlavičkaContent-Typeje jedna z následujících: application/x-www-form-urlencodedmultipart/form-datatext/plain- Nejsou nastaveny žádné vlastní hlavičky.
Příklad jednoduchého požadavku:
GET /resource HTTP/1.1
Origin: http://www.example.com
Příklad odpovědi serveru povolující původ:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.example.com
Content-Type: application/json
{
"data": "Some data"
}
Pokud je hlavička Access-Control-Allow-Origin přítomna a její hodnota se shoduje s původem požadavku nebo je nastavena na *, prohlížeč povolí skriptu přístup k datům odpovědi. V opačném případě prohlížeč zablokuje přístup k odpovědi a v konzoli se zobrazí chybová zpráva.
2. Preflight požadavky
Požadavek je považován za "preflighted", pokud nesplňuje kritéria pro jednoduchý požadavek. To se obvykle stává, když požadavek používá jinou metodu HTTP (např. PUT, DELETE), nastavuje vlastní hlavičky nebo používá Content-Type jiný než povolené hodnoty.
Před odesláním skutečného požadavku prohlížeč nejprve odešle požadavek OPTIONS na server. Tento "preflight" požadavek obsahuje následující hlavičky:
Origin: Původ požadující stránky.Access-Control-Request-Method: Metoda HTTP, která bude použita ve skutečném požadavku (např.PUT,DELETE).Access-Control-Request-Headers: Čárkami oddělený seznam vlastních hlaviček, které budou odeslány ve skutečném požadavku.
Příklad preflight požadavku:
OPTIONS /resource HTTP/1.1
Origin: http://www.example.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header, Content-Type
Server musí na požadavek OPTIONS odpovědět s následujícími hlavičkami:
Access-Control-Allow-Origin: Původ, který má povoleno provést požadavek (nebo*pro povolení jakéhokoli původu).Access-Control-Allow-Methods: Čárkami oddělený seznam metod HTTP, které jsou povoleny pro požadavky mezi různými původy (např.GET,POST,PUT,DELETE).Access-Control-Allow-Headers: Čárkami oddělený seznam vlastních hlaviček, které je povoleno odeslat v požadavku.Access-Control-Max-Age: Počet sekund, po které může být odpověď na preflight požadavek uložena v mezipaměti prohlížeče.
Příklad odpovědi serveru na preflight požadavek:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://www.example.com
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: X-Custom-Header, Content-Type
Access-Control-Max-Age: 86400
Pokud odpověď serveru na preflight požadavek naznačuje, že skutečný požadavek je povolen, prohlížeč následně odešle skutečný požadavek. V opačném případě prohlížeč požadavek zablokuje a zobrazí chybovou zprávu.
Implementace CORS na straně serveru
CORS je primárně implementován na straně serveru nastavením příslušných HTTP hlaviček v odpovědi. Konkrétní detaily implementace se budou lišit v závislosti na použité serverové technologii.
Příklad s použitím Node.js a Express:
const express = require('express');
const cors = require('cors');
const app = express();
// Povolit CORS pro všechny původy
app.use(cors());
// Alternativně, nakonfigurujte CORS pro specifické původy
// const corsOptions = {
// origin: 'http://www.example.com'
// };
// app.use(cors(corsOptions));
app.get('/resource', (req, res) => {
res.json({ message: 'Toto je zdroj s povoleným CORS' });
});
app.listen(3000, () => {
console.log('Server naslouchá na portu 3000');
});
Middleware cors zjednodušuje proces nastavování CORS hlaviček v Expressu. Můžete povolit CORS pro všechny původy pomocí cors() nebo jej nakonfigurovat pro specifické původy pomocí cors(corsOptions).
Příklad s použitím Pythonu a Flasku:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
@app.route("/resource")
def hello():
return {"message": "Toto je zdroj s povoleným CORS"}
if __name__ == '__main__':
app.run(debug=True)
Rozšíření flask_cors poskytuje jednoduchý způsob, jak povolit CORS v aplikacích Flask. Můžete povolit CORS pro všechny původy předáním app do CORS(). Je také možná konfigurace pro specifické původy.
Příklad s použitím Javy a Spring Boot:
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("/resource")
.allowedOrigins("http://www.example.com")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("Content-Type", "X-Custom-Header")
.allowCredentials(true)
.maxAge(3600);
}
}
Ve Spring Boot můžete konfigurovat CORS pomocí WebMvcConfigurer. To umožňuje jemnou kontrolu nad povolenými původy, metodami, hlavičkami a dalšími nastaveními CORS.
Přímé nastavení CORS hlaviček (Obecný příklad)
Pokud nepoužíváte žádný framework, můžete hlavičky nastavit přímo ve vašem serverovém kódu (např. PHP, Ruby on Rails atd.):
Osvědčené postupy pro CORS
Pro zajištění bezpečné a efektivní komunikace mezi různými původy dodržujte tyto osvědčené postupy:
- Vyhněte se používání
Access-Control-Allow-Origin: *v produkčním prostředí: Povolení přístupu k vašim zdrojům všem původům může představovat bezpečnostní riziko. Místo toho specifikujte přesné povolené původy. - Používejte HTTPS: Vždy používejte HTTPS pro požadující i obsluhující původ, abyste chránili data během přenosu.
- Validujte vstup: Vždy validujte a sanitizujte data přijatá z požadavků mezi různými původy, abyste předešli útokům typu injection.
- Implementujte řádné ověřování a autorizaci: Ujistěte se, že pouze autorizovaní uživatelé mají přístup k citlivým zdrojům.
- Ukládejte odpovědi na preflight požadavky do mezipaměti: Použijte
Access-Control-Max-Agepro ukládání odpovědí na preflight požadavky do mezipaměti a snižte tak počet požadavkůOPTIONS. - Zvažte použití přihlašovacích údajů (credentials): Pokud vaše API vyžaduje ověření pomocí cookies nebo HTTP autentizace, musíte na serveru nastavit hlavičku
Access-Control-Allow-Credentialsnatruea ve vašem JavaScriptovém kódu nastavit volbucredentialsna'include'(např. při použitífetchneboXMLHttpRequest). Při použití této volby buďte extrémně opatrní, protože může způsobit bezpečnostní zranitelnosti, pokud není správně ošetřena. Také, když je Access-Control-Allow-Credentials nastaveno na true, Access-Control-Allow-Origin nemůže být nastaveno na "*". Musíte explicitně specifikovat povolený původ (původy). - Pravidelně kontrolujte a aktualizujte konfiguraci CORS: Jak se vaše aplikace vyvíjí, pravidelně kontrolujte a aktualizujte svou konfiguraci CORS, abyste zajistili, že zůstane bezpečná a vyhovuje vašim potřebám.
- Pochopte důsledky různých konfigurací CORS: Buďte si vědomi bezpečnostních důsledků různých konfigurací CORS a zvolte konfiguraci, která je vhodná pro vaši aplikaci.
- Testujte svou implementaci CORS: Důkladně testujte svou implementaci CORS, abyste se ujistili, že funguje podle očekávání a že nezavádí žádné bezpečnostní zranitelnosti. Použijte vývojářské nástroje prohlížeče k inspekci síťových požadavků a odpovědí a použijte automatizované testovací nástroje k ověření chování CORS.
Příklad: Použití Fetch API s CORS
Zde je příklad, jak použít fetch API k provedení požadavku mezi různými původy:
fetch('https://api.example.com/data', {
method: 'GET',
mode: 'cors', // Říká prohlížeči, že se jedná o CORS požadavek
headers: {
'Content-Type': 'application/json',
'X-Custom-Header': 'value'
}
})
.then(response => {
if (!response.ok) {
throw new Error('Síťová odpověď nebyla v pořádku');
}
return response.json();
})
.then(data => {
console.log(data);
})
.catch(error => {
console.error('Nastal problém s operací fetch:', error);
});
Volba mode: 'cors' říká prohlížeči, že se jedná o CORS požadavek. Pokud server nepovolí daný původ, prohlížeč zablokuje přístup k odpovědi a bude vyvolána chyba.
Pokud používáte přihlašovací údaje (např. cookies), musíte nastavit volbu credentials na 'include':
fetch('https://api.example.com/data', {
method: 'GET',
mode: 'cors',
credentials: 'include', // Zahrnout cookies do požadavku
headers: {
'Content-Type': 'application/json'
}
})
.then(response => {
// ...
});
CORS a JSONP
JSON with Padding (JSONP) je starší technika pro obcházení Same-Origin Policy. Funguje dynamickým vytvořením značky <script>, která načítá data z jiné domény. Ačkoli JSONP může být v určitých situacích užitečný, má významná bezpečnostní omezení a mělo by se mu pokud možno vyhnout. CORS je preferovaným řešením pro komunikaci mezi různými původy, protože poskytuje bezpečnější a flexibilnější mechanismus.
Klíčové rozdíly mezi CORS a JSONP:
- Bezpečnost: CORS je bezpečnější než JSONP, protože umožňuje serveru kontrolovat, které původy mají povolen přístup k jeho zdrojům. JSONP neposkytuje žádnou kontrolu původu.
- Metody HTTP: CORS podporuje všechny metody HTTP (např.
GET,POST,PUT,DELETE), zatímco JSONP podporuje pouze požadavkyGET. - Zpracování chyb: CORS poskytuje lepší zpracování chyb než JSONP. Když se požadavek CORS nezdaří, prohlížeč poskytuje podrobné chybové zprávy. Zpracování chyb v JSONP je omezeno na detekci, zda se skript úspěšně načetl.
Řešení problémů s CORS
Problémy s CORS mohou být frustrující při ladění. Zde je několik běžných tipů pro řešení problémů:
- Zkontrolujte konzoli prohlížeče: Konzole prohlížeče obvykle poskytuje podrobné chybové zprávy o problémech s CORS.
- Prozkoumejte síťové požadavky: Použijte vývojářské nástroje prohlížeče k prozkoumání HTTP hlaviček požadavku i odpovědi. Ověřte, že hlavičky
OriginaAccess-Control-Allow-Originjsou nastaveny správně. - Ověřte konfiguraci na straně serveru: Dvakrát zkontrolujte svou serverovou konfiguraci CORS, abyste se ujistili, že povoluje správné původy, metody a hlavičky.
- Vymažte mezipaměť prohlížeče: Někdy mohou problémy s CORS způsobovat odpovědi na preflight požadavky uložené v mezipaměti. Zkuste vymazat mezipaměť prohlížeče nebo použít anonymní okno.
- Použijte CORS proxy: V některých případech může být nutné použít CORS proxy k obejití omezení CORS. Mějte však na paměti, že použití CORS proxy může přinést bezpečnostní rizika.
- Zkontrolujte nesprávné konfigurace: Hledejte běžné nesprávné konfigurace, jako je chybějící hlavička
Access-Control-Allow-Origin, nesprávné hodnotyAccess-Control-Allow-MethodsneboAccess-Control-Allow-Headers, nebo nesprávná hlavičkaOriginv požadavku.
Závěr
Cross-Origin Resource Sharing (CORS) je základním mechanismem pro umožnění bezpečné komunikace mezi různými původy v JavaScriptových aplikacích. Pochopením Same-Origin Policy, pracovního postupu CORS a různých souvisejících HTTP hlaviček mohou vývojáři efektivně implementovat CORS k ochraně svých aplikací před bezpečnostními zranitelnostmi a zároveň povolit legitimní požadavky mezi různými původy. Dodržování osvědčených postupů pro konfiguraci CORS a pravidelná kontrola vaší implementace jsou klíčové pro udržení bezpečné a robustní webové aplikace.
Tento komplexní průvodce poskytuje pevný základ pro pochopení a implementaci CORS. Nezapomeňte se obrátit na oficiální dokumentaci a zdroje pro vaši specifickou serverovou technologii, abyste zajistili, že CORS implementujete správně a bezpečně.