CORS: sdílení zdrojů napříč doménami

CORS: Zdieľanie zdrojov medzi doménami

CORS v kontextu webu: proč existuje a co řeší

CORS (Cross-Origin Resource Sharing) je mechanismus HTTP, který umožňuje bezpečné sdílení zdrojů mezi různými původy (origins). Opírá se o hlavičky v požadavcích a odpovědích, které prohlížeč respektuje při čtení dat z jiné domény, subdomény, portu nebo protokolu. CORS rozšiřuje tzv. Same-Origin Policy (SOP) tak, aby webové aplikace mohly přistupovat k API a statickým zdrojům napříč doménami, aniž by tím byla ohrožena bezpečnost.

Origin a Same-Origin Policy: základní pojmy

  • Origin = kombinace scheme://host:port (např. https://app.example.com:443).
  • Same-Origin Policy brání skriptům načteným z jednoho původu číst citlivé odpovědi z jiného původu.
  • CORS umožňuje kontrolované prolomení této bariéry prostřednictvím deklarativních hlaviček na straně serveru.

Aktéři a odpovědnosti

  • Prohlížeč vynucuje pravidla CORS a v případě jejich porušení zablokuje přístup k odpovědi (JS nedostane tělo, konzole vypíše chybu).
  • Server cílového zdroje rozhoduje, komu (kterému původu) a za jakých podmínek poskytne přístup, a to pomocí hlaviček CORS.
  • CDN/Proxy může měnit hlavičky, ukládat odpovědi na preflight do mezipaměti a ovlivnit chování (pozor na Vary).

Typy požadavků: jednoduché, preflight a credentialed

  • Jednoduché požadavky (bez preflightu): metody GET, HEAD, POST s bezpečnými hlavičkami typu simple (např. Accept, Content-Type s hodnotami typu application/x-www-form-urlencoded, multipart/form-data nebo text/plain), bez vlastních nestandardních hlaviček.
  • Preflight: prohlížeč nejprve odešle OPTIONS s hlavičkami Origin, Access-Control-Request-Method a případně Access-Control-Request-Headers. Server musí požadavek povolit, jinak se hlavní požadavek neprovede.
  • Credentialed (s přihlašovacími údaji): pokud klient odesílá cookies/HTTP auth/klientské certifikáty (fetch s credentials: "include"), server musí odpovědět hlavičkou Access-Control-Allow-Credentials: true a nesmí použít Access-Control-Allow-Origin: *; musí uvést konkrétní původ.

Klíčové hlavičky CORS a jejich význam

  • Origin: automaticky přidávaná klientem; identifikuje původ volajícího.
  • Access-Control-Allow-Origin: odpověď serveru s povoleným původem (konkrétní https://example.com nebo * u požadavků bez přihlašovacích údajů).
  • Access-Control-Allow-Methods: metody povolené při preflightu (GET, POST, PUT, DELETE, OPTIONS…).
  • Access-Control-Allow-Headers: hlavičky, které nejsou simple a jsou povolené v hlavním požadavku (např. Authorization, X-Requested-With).
  • Access-Control-Expose-Headers: seznam hlaviček, které lze číst z JS (bez něj jsou viditelné pouze hlavičky z safe list).
  • Access-Control-Allow-Credentials: true, pokud jsou povoleny cookies/přihlašovací údaje.
  • Access-Control-Max-Age: doba, po kterou může prohlížeč ukládat výsledek preflightu do mezipaměti (snížení latence; prohlížeče mají vlastní horní limity).
  • Vary: Origin: mimořádně důležité při použití CDN – odpověď se má lišit podle Origin. Bez toho riskujete otrávení mezipaměti nebo únik hlaviček.

Životní cyklus preflightu krok za krokem

  1. JS (např. fetch) chce odeslat PUT s hlavičkou Authorization.
  2. Prohlížeč odešle OPTIONS na stejnou URL s hlavičkou Origin a hlavičkami Access-Control-Request-*.
  3. Server odpoví např. Access-Control-Allow-Origin: https://app.example.com, Access-Control-Allow-Methods: PUT, Access-Control-Allow-Headers: Authorization, Access-Control-Max-Age: 600.
  4. Prohlížeč si výsledek preflightu dočasně zapamatuje a provede hlavní požadavek.

Obvyklé topologie: SPA, API a CDN

  • SPA na doméně A volá API na doméně B: na B nastavte, aby podle seznamu povolených původů vracela Access-Control-Allow-Origin pouze pro známé původy a přidala Vary: Origin.
  • CDN před API: zajistěte, aby CDN respektovala a předávala Origin původnímu serveru; bezpečně ukládejte odpovědi do mezipaměti podle Vary a zvažte ukládání preflightů do mezipaměti.
  • Statické assety (fonty, obrázky, video): pokud se používají napříč doménami (např. fonty), přidejte Access-Control-Allow-Origin a správný Content-Type.

Konfigurace: návrhové vzory bez bezpečnostních děr

  • Reflexe původu pomocí seznamu povolených původů: server zkontroluje Origin; pokud je na seznamu, vrátí Access-Control-Allow-Origin s danou hodnotou a doplní Vary: Origin. Nikdy bez kontroly nereflektujte libovolný Origin.
  • Credentialed API: použijte konkrétní Access-Control-Allow-Origin (nikoli *) a Access-Control-Allow-Credentials: true. Omezte Allow-Methods a Allow-Headers na minimum.
  • Minimalizace preflightů: upřednostňujte metody a hlavičky typu simple; JSON posílejte jako text/plain pouze tehdy, pokud to bezpečnostní politika dovoluje a víte, co děláte. Častěji je lepší preflight přijmout a správně jej ukládat do mezipaměti.

Příklady hlaviček pro odpovědi API

Bez přihlašovacích údajů, více domén přes CDN: Access-Control-Allow-Origin: *, Access-Control-Expose-Headers: ETag, Link, Vary: Origin (pokud později přejdete na politiku podle jednotlivých původů).

S přihlašovacími údaji pouze pro app: Access-Control-Allow-Origin: https://app.example.com, Access-Control-Allow-Credentials: true, Access-Control-Expose-Headers: X-RateLimit-Remaining, Vary: Origin.

Odpověď na preflight: Access-Control-Allow-Origin: https://app.example.com, Access-Control-Allow-Methods: GET, POST, Access-Control-Allow-Headers: Authorization, Content-Type, Access-Control-Max-Age: 600, Vary: Origin, Access-Control-Request-Method, Access-Control-Request-Headers.

Přesměrování, mezipaměť a CORS

  • Přesměrování mohou způsobit selhání CORS, pokud mezilehlý článek odstraní hlavičky nebo změní protokol/hostitele/port. Ideální je odpovídat přímo, bez 302/301, zejména u preflightu.
  • Mezipaměť CDN: vždy zvažte použití Vary pro Origin a případně také pro Access-Control-Request-* u preflightu.
  • ETag a podmíněné požadavky (If-None-Match) fungují s CORS, ale pouze pokud jsou hlavičky CORS zachovány i při odpovědi 304.

Bezpečnostní souvislosti: CORS ≠ autentizace

  • CORS je mechanismus prohlížeče; nenahrazuje autentizaci ani autorizaci. Server musí i nadále ověřovat tokeny, relace a ACL.
  • Nikdy nepovolujte * společně s Allow-Credentials: true. Prohlížeče takovou kombinaci blokují; jde také o bezpečnostní zásadu.
  • Odlišujte CORS od politik CSP, COOP/COEP/CORP – tyto související mechanismy řeší jiné oblasti (izolaci, možnost načítání, vkládání obsahu z jiného původu).

Vliv na SEO, AIO/AEO a optimalizaci pro LLM

  • Indexace a vykreslování: Googlebot se službou Web Rendering Service sice spouští JS, volání API přes CORS však mohou selhat a způsobit neúplný obsah. Důležitá data pro SEO (např. texty produktů, FAQ) raději vykreslujte pomocí SSR/SSG a nezávisle na běhovém volání přes CORS.
  • Strukturovaná data: nenačítejte JSON-LD pomocí běhového cross-origin fetch; vložte ho přímo do HTML.
  • AIO/AEO (odpovědi asistentů): pokud widgety (HowTo, FAQ, Product) závisejí na médiích z jiného původu (obrázky, video), povolte CORS na doméně s assety, jinak mohou vložené komponenty v SPA zobrazovat stav „broken“.
  • Výkon: preflight přidává RTT; při vysokém podílu volání CORS roste TTI a zhoršují se Core Web Vitals. Zvažte slučování volání API, HTTP/2/3, ukládání preflightů do mezipaměti a proxy same-origin.

Diagnostika a testování

  • DevTools → Network: filtrujte OPTIONS a zkontrolujte přítomnost správných hlaviček CORS při preflightu i v hlavní odpovědi.
  • curl: simulujte preflight např. pomocí curl -i -X OPTIONS https://api.example.com/resource -H "Origin: https://app.example.com" -H "Access-Control-Request-Method: PUT" -H "Access-Control-Request-Headers: Authorization".
  • Logy serveru/CDN: zapněte protokolování požadavků OPTIONS, sledujte zásahy do mezipaměti a její minutí i chování hlavičky Vary.
  • Monitorování: měřte podíl chyb CORS v JS (obslužná funkce error objektu window) a porovnávejte ho s konverzemi.

Nejčastější chyby a jejich řešení

  1. „No ‚Access-Control-Allow-Origin‘ header is present“ – server nevrací povolení pro daný původ; přidejte správnou hlavičku Access-Control-Allow-Origin a Vary: Origin.
  2. „The value of the ‚Access-Control-Allow-Origin‘ header contains ‚*‘ when credentials flag is true“ – místo * použijte konkrétní původ a ponechte Allow-Credentials: true.
  3. Preflight blokovaný odpovědí 301/302 – odpovídejte přímo nebo přesměrujte pouze hlavní požadavek; preflight by měl dostat konečnou odpověď s hlavičkami CORS.
  4. Chybějící hlavičky při 304 – i odpověď 304 musí obsahovat relevantní hlavičky CORS.
  5. CDN odstraňuje hlavičky – povolte a předávejte Origin a zachovávejte hlavičky CORS na edge.
  6. Příliš široké Allow-Headers/Methods – zužte seznam na nezbytné hodnoty; tím snížíte útočnou plochu.

Optimalizace výkonu: jak snížit latenci CORS

  • Slučujte volání a upřednostňujte GET pro čitelné zdroje s agresivním nastavením cache-control.
  • Pro preflight použijte rozumnou hodnotu Access-Control-Max-Age a zvažte ukládání do mezipaměti CDN.
  • Přesuňte API pod stejný původ (reverzní proxy, /api na stejné doméně), pokud je to možné.
  • Omezte vlastní hlavičky; Authorization často spouští preflight – zvažte alternativní modely (např. cookie s SameSite podle potřeby a ochranou proti CSRF), ale vždy s ohledem na bezpečnost.

Specifika cookies a SameSite

  • U cookies pro cross-site požadavky bývá nutné nastavení SameSite=None; Secure. Jinak prohlížeč cookie neodešle, i když CORS povoluje přihlašovací údaje.
  • Nezapomeňte sladit doménu cookie (Domain) se způsobem, jakým ji chcete používat napříč subdoménami.

Fonty, obrázky a média napříč doménami

  • Webové fonty vyžadují správné hlavičky CORS na doméně s assety (Access-Control-Allow-Origin), jinak mohou být zablokovány.
  • U <img> se obrázek sice načte, ale čtení pixelových dat z canvasu bez CORS vede k jeho znečištění (ochrana soukromí).
  • Video a audio streamy mohou vyžadovat kompatibilní CORS také pro požadavky Range a správné typy MIME.

Integrace do vývojového procesu

  • Infrastruktura jako kód: definujte zásady CORS v konfiguraci Nginx/Apache/CloudFront/S3 jako součást repozitáře.
  • Testy: přidejte integrační testy, které ověřují přítomnost správných hlaviček v běžných scénářích i při preflightu.
  • Observabilita: metriky provozu OPTIONS, chybovosti a podílu zásahů do mezipaměti preflightů na CDN.

Kontrolní seznam pro bezpečné nasazení CORS

  • Máte výslovný seznam povolených původů (včetně zástupných znaků pro subdomény, pokud je skutečně potřebujete).
  • Všechny odpovědi (200/4xx/5xx/304) obsahují konzistentní hlavičky CORS.
  • Preflight se obejde bez přesměrování a uvádí přesně ty metody a hlavičky, které potřebujete.
  • Ve scénářích s přihlašovacími údaji nepoužíváte * a vracíte Vary: Origin.
  • CDN předává Origin a respektuje Vary; preflight se ukládá do mezipaměti v rozumné míře.
  • DevTools a automatizované testy nehlásí chyby CORS v kritických uživatelských scénářích.

Shrnutí

CORS je nezbytnou součástí moderního webu, která umožňuje bezpečné propojení SPA, API a assetů napříč doménami. Správně nastavené hlavičky, rozumné ukládání preflightů do mezipaměti, důsledná bezpečnostní politika a začlenění kontrol do CI/CD snižují latenci, chrání data a stabilizují vykreslování – což v konečném důsledku prospívá SEO, AIO/AEO i celkové použitelnosti webu.