CORS: co je a proč prohlížeč blokuje API | POLPROG Přejít na obsah

CORS: co je a proč prohlížeč blokuje API

CORS není mechanismus, který jednoduše blokuje spojení s API. Je to protokol prohlížeče postavený na same-origin policy, který rozhoduje, zda JavaScript z jednoho originu smí číst odpověď z jiného originu. V některých případech je HTTP request odeslán a prohlížeč pouze zablokuje přístup skriptu k odpovědi. V jiných případech nejprve odešle preflight OPTIONS a podle výsledku rozhodne, zda odešle skutečný request.

Publikováno Autor Čas čtení 10 min čtení

CORS není mechanismus, který jednoduše blokuje spojení s API. Je to protokol prohlížeče postavený na same-origin policy, který rozhoduje, zda JavaScript z jednoho originu smí číst odpověď z jiného originu. V některých případech je HTTP request odeslán a prohlížeč pouze zablokuje přístup skriptu k odpovědi. V jiných případech nejprve odešle preflight OPTIONS a podle výsledku rozhodne, zda odešle skutečný request.

Na této stránce
  1. 1CORS začíná u same-origin policy
  2. 2Co přesně znamená origin
  3. 3Co opravdu znamená, že prohlížeč blokuje API
  4. 4Jednoduché requesty: kdy se preflight nepoužije
  5. 5Preflight OPTIONS: co prohlížeč ověřuje
  6. 6Nejdůležitější CORS headers
  7. 7`Access-Control-Allow-Origin`: wildcard nebo konkrétní origin
  8. 8Cookies a credentials: častý zdroj problémů
  9. 9Proč `mode: "no-cors"` obvykle nic neopraví
  10. 10Proč curl, Postman nebo backend mohou fungovat
  11. 11CORS nenahrazuje CSRF ochranu ani autorizaci
  12. 12Časté chyby a diagnostika
  13. 13Nebezpečné CORS konfigurace
  14. 14Výkon: cena preflightu a `Access-Control-Max-Age`
  15. 15Praktická konfigurace a checklist nasazení

CORS začíná u same-origin policy

Same-origin policy je základní bezpečnostní mechanismus prohlížeče. Omezuje možnost dokumentu nebo skriptu číst data z jiného originu a brání například škodlivému webu číst data ze služby, kde je uživatel přihlášen. [3]

CORS, Cross-Origin Resource Sharing, je HTTP mechanismus, kterým server tuto zásadu kontrolovaně uvolňuje a určuje, které originy mohou odpověď číst. Fetch Standard ho popisuje jako opt-in protokol. [1][2]

Co přesně znamená origin

StránkaCílová URLVztahProč
https://app.example.comhttps://app.example.com/apiStejný originStejné schéma, host a port
https://app.example.comhttps://api.example.comJiný originJiný host
https://app.example.comhttp://app.example.comJiný originJiné schéma
https://app.example.comhttps://app.example.com:8443Jiný originJiný port
https://app.example.comhttps://app.example.com/v2Stejný originMění se pouze cesta

Origin je dán schématem, hostem a portem. Dvě URL jsou same-origin pouze tehdy, když se shodují všechny tři hodnoty. Cesta nehraje roli. [3][4]

`https://app.example.com` a `https://api.example.com` jsou tedy různé originy. Stejně tak HTTP proti HTTPS nebo různé porty. [4]

Same-origin a same-site nejsou totožné pojmy. To je důležité u cookies, protože `SameSite` používá pojem site, zatímco CORS používá origin. [13]

Co opravdu znamená, že prohlížeč blokuje API

Tvrzení, že prohlížeč blokuje request, je často příliš zjednodušené. U jednoduchého cross-origin requestu může request odeslat, přijmout platnou HTTP odpověď a teprve poté ji nezpřístupnit JavaScriptu, pokud CORS kontrola selže. [1][6]

U requestů s preflightem je průběh jiný. Nejprve se posílá `OPTIONS`. Pokud preflight selže, skutečný request se neodešle. [2][5][6]

Tento rozdíl je důležitý u operací měnících data. CORS chyba automaticky neznamená, že backend žádný request nedostal.

Jednoduché requesty: kdy se preflight nepoužije

MetodaPříklad headersJednoduchý requestDůsledek
GETAcceptAnoBez preflightu
POSTContent-Type: text/plainAnoBez preflightu
POSTContent-Type: application/jsonNeJSON vyvolá preflight
PUTContent-Type: application/jsonNeMetoda vyvolá preflight
GETAuthorization: Bearer ...NeHeader vyvolá preflight

Request je jednoduchý jen při splnění CORS safelist. Povolené metody jsou `GET`, `HEAD` a `POST`. Ručně nastavené headers musí být safelisted a `Content-Type` smí být jen `application/x-www-form-urlencoded`, `multipart/form-data` nebo `text/plain`. [1]

Běžný `POST` s `Content-Type: application/json` není jednoduchý a obvykle vyvolá preflight. Stejně tak `PUT`, `DELETE` nebo vlastní header typu `X-Request-ID`. [1][11]

Preflight OPTIONS: co prohlížeč ověřuje

Preflight je automatický `OPTIONS` request. Prohlížeč posílá `Origin`, `Access-Control-Request-Method` a podle potřeby `Access-Control-Request-Headers`. Server odpoví povolenými originy, metodami a headers. [2][5]

Pokud chce aplikace poslat `DELETE` s `Authorization`, může prohlížeč nejprve ověřit, zda daný origin smí použít tuto metodu a header. Teprve kladná odpověď dovolí skutečný request. [5]

Preflight přidává další síťový round trip, ale výsledek lze uložit do samostatné CORS preflight cache mimo běžnou HTTP cache. [5][10]

Nejdůležitější CORS headers

HeaderSměrÚčel
OriginRequestOrigin, který request iniciuje
Access-Control-Allow-OriginResponseOrigin, jehož kód může odpověď obdržet
Access-Control-Allow-MethodsPreflight responseMetody povolené preflightem
Access-Control-Allow-HeadersPreflight responseRequest headers povolené preflightem
Access-Control-Allow-CredentialsResponsePovolení zpřístupnit odpověď s credentials
Access-Control-Expose-HeadersResponseDalší response headers dostupné JavaScriptu
Access-Control-Max-AgePreflight responseDoba cache výsledku preflightu
Vary: OriginResponseInformace pro cache, že odpověď závisí na Origin

`Origin` je request header označující iniciující origin. `Access-Control-Allow-Origin` je serverový response header, který říká prohlížeči, zda může odpověď sdílet s kódem z daného originu. [1][2][8]

`Access-Control-Allow-Methods` a `Access-Control-Allow-Headers` jsou důležité hlavně při preflightu. `Access-Control-Allow-Credentials` povoluje zpřístupnění odpovědi s credentials a `Access-Control-Expose-Headers` zpřístupní JavaScriptu další response headers. [1][2]

Pokud server nastavuje `Access-Control-Allow-Origin` dynamicky, MDN doporučuje také `Vary: Origin`. [1]

`Access-Control-Allow-Origin`: wildcard nebo konkrétní origin

`Access-Control-Allow-Origin: *` dovoluje sdílení odpovědi s libovolným originem u requestů bez credentials. Pro skutečně veřejné API to může být správně. [2][8]

U privátních nebo citlivých endpointů by povolená množina měla být co nejmenší. MDN a OWASP doporučují konkrétní originy, pokud není globální přístup nutný. [14][17]

Při více povolených originech má server porovnat příchozí `Origin` s allowlistem a vrátit jen schválenou hodnotu. Slepé zrcadlení libovolného originu je nebezpečné. [8][16]

Cookies a credentials: častý zdroj problémů

Fetch může použít `credentials: "include"` pro credentials v cross-origin requests. To samo nestačí. Server musí vrátit `Access-Control-Allow-Credentials: true` a konkrétní `Access-Control-Allow-Origin`. `*` zde není povoleno. [2][6][9]

Cookies podléhají také vlastním pravidlům. `SameSite` může zabránit jejich odeslání při cross-site requestu a `SameSite=None` vyžaduje `Secure`. [13]

CORS a `SameSite` řeší různé problémy. CORS může být správně, ale cookie chybí, nebo cookie může odejít a CORS stále zablokuje JavaScriptu odpověď.

Proč `mode: "no-cors"` obvykle nic neopraví

`fetch(..., { mode: "no-cors" })` neobchází CORS, pokud aplikace potřebuje odpověď číst. Metody a headers jsou omezené a odpověď je opaque. JavaScript nemůže číst body ani headers a viditelný status je `0`. [6][7][11]

`no-cors` má specializované použití, například některé scénáře Service Worker, ale pro běžné JSON API je obvykle špatnou volbou. [6]

Pokud externí API CORS nenabízí, vlastní backend nebo proxy může provést request server-to-server. [11][12]

Proč curl, Postman nebo backend mohou fungovat

Same-origin policy a CORS vynucuje prohlížeč. HTTP klient mimo tento model stejnou CORS kontrolou neprochází. Proto může endpoint fungovat v curl nebo API nástroji a z JavaScriptu stránky být blokovaný. [2][3][16]

To také ukazuje, proč CORS není autentizace API. Klient mimo prohlížeč může nastavit vlastní `Origin`, takže OWASP varuje před použitím tohoto headeru jako důkazu identity. [16]

API stále potřebuje autorizaci, tokeny, sessions, kontroly oprávnění a serverovou validaci.

CORS nenahrazuje CSRF ochranu ani autorizaci

Same-origin policy omezuje hlavně cross-origin čtení. Formuláře a některé jednoduché requesty lze přesto posílat cross-origin, takže cookie-based aplikace stále potřebují CSRF ochranu. [3][15]

OWASP výslovně doporučuje nespoléhat pouze na CORS nebo `Origin` při ochraně citlivých zdrojů. Autentizace a autorizace jsou nutné nezávisle. [16]

CORS odpovídá na otázku, zda prohlížeč může zpřístupnit odpověď kódu z originu. Neřeší, zda uživatel nebo klient smí operaci provést.

Časté chyby a diagnostika

Chybějící `Access-Control-Allow-Origin` je běžná chyba. Další příčiny jsou nepovolená metoda, chybějící položka v `Access-Control-Allow-Headers`, `*` s credentials, chybná OPTIONS odpověď nebo redirecty v CORS flow. [11][12]

JavaScript dostává záměrně jen omezené detaily. Pro přesnou diagnózu je důležitější konzole a Network panel. [1][11]

`CORS request did not succeed` může způsobit i DNS, timeout, odmítnuté spojení, TLS, mixed content nebo browser extension. [11]

  • Zkontrolujte přesný frontend origin: schéma, host a port.
  • Zkontrolujte `OPTIONS`, pokud existuje.
  • Ověřte status a `Access-Control-Allow-*` preflight odpovědi.
  • Ověřte, že i skutečná odpověď obsahuje požadované CORS headers.
  • U cookies zkontrolujte `credentials`, `Access-Control-Allow-Credentials`, `SameSite` a `Secure`.
  • Zkontrolujte redirecty, TLS, mixed content a síťové chyby.
  • Porovnejte browser request s fungujícím curl nebo API-tool requestem.

Nebezpečné CORS konfigurace

Slepé vracení příchozího `Origin` je nebezpečné, pokud requesty s credentials vracejí citlivá data. Útočník může ovládat vlastní origin a pokusit se číst odpovědi v kontextu přihlášeného uživatele. [16]

Příliš široké regulární výrazy a důvěra všem subdoménám jsou také rizikové, pokud lze některou subdoménu převzít. OWASP doporučuje přesný allowlist. [16][17]

`Access-Control-Allow-Origin: *` není automaticky zranitelnost u zcela veřejných dat bez credentials. Problémem je politika širší, než je skutečně potřeba. [8][17]

Výkon: cena preflightu a `Access-Control-Max-Age`

Preflight přidává před skutečný request další `OPTIONS` a může zvýšit latenci. Jeho výsledek lze cacheovat pomocí `Access-Control-Max-Age` v samostatné preflight cache. [5][10]

MDN uvádí bez headeru výchozí hodnotu 5 sekund. Prohlížeče mají vlastní maxima. Firefox omezuje na 86400 sekund a Chromium od verze 76 na 7200 sekund. [10]

Stabilní politiky lze cacheovat, ale ne tak dlouho, aby bylo obtížné rychle odvolat omylem příliš široké povolení.

Praktická konfigurace a checklist nasazení

Nejprve rozhodněte, zda endpoint má být vůbec dostupný cross-origin. Pokud ne, CORS headers nepřidávejte. Pokud ano, definujte allowlist originů, potřebné metody a headers a potřebu credentials. [14][17]

U dynamického allowlistu vraťte jen ověřený origin a přidejte `Vary: Origin`. S credentials používejte konkrétní origin a `Access-Control-Allow-Credentials: true`. Frontend toto serverové rozhodnutí nemůže nahradit. [1][2]

Po nasazení otestujte jednoduchý request, preflight, scénář s cookie, nepovolený origin a skutečné chyby v DevTools.

  • Je cross-origin přístup opravdu nutný?
  • Které přesné originy mají být povoleny?
  • Jsou potřeba credentials?
  • Které metody a request headers jsou potřeba?
  • Dostane se `OPTIONS` do aplikace a odpoví správně?
  • Obsahuje skutečná odpověď správné CORS headers?
  • Obsahují dynamické odpovědi `Vary: Origin`?
  • Vyžaduje endpoint stále běžnou autentizaci a autorizaci?
  • Byla politika otestována s povoleným i nepovoleným originem?

CORS je vhodné chápat jako pravidlo prohlížeče pro zpřístupnění odpovědí, ne jako univerzální bezpečnostní hranici API. Nejprve určete origin frontendu a API, poté zjistěte, zda je request jednoduchý nebo potřebuje preflight, a nakonec zkontrolujte OPTIONS a CORS headers skutečné odpovědi. Bezpečná konfigurace povoluje jen potřebné originy, metody a headers, zatímco autentizace a autorizace zůstávají v aplikaci.

CORS Same-Origin Policy Web Security HTTP API Fetch API Preflight Cookies CSRF Frontend

Často kladené otázky

Co je CORS?

CORS je HTTP protokol používaný prohlížeči k řízenému sdílení odpovědí mezi různými originy. Server pomocí headers určuje, které originy mohou odpověď číst. [1][2]

Proč API funguje v Postmanu, ale ne v prohlížeči?

Protože CORS vynucuje prohlížeč jako součást same-origin policy. HTTP klienti mimo prohlížeč stejnému mechanismu nepodléhají. [2][3][16]

Blokuje CORS vždy odeslání requestu?

Ne. Jednoduchý request může být odeslán a browser pouze zablokuje JavaScriptu čtení odpovědi. Když selže povinný preflight, skutečný request se neodešle. [1][5][6]

Co spouští preflight?

Například metody mimo GET, HEAD, POST, vlastní headers nebo Content-Type: application/json. Prohlížeč nejprve posílá OPTIONS. [1][5]

Patří Access-Control-Allow-Origin do frontendu?

Ne. Je to serverový response header. Frontend si tímto headerem nemůže sám udělit oprávnění. [1][8][12]

Opraví mode: "no-cors" CORS?

Ne u běžného API, jehož data potřebujete číst. Odpověď je opaque a body, headers ani běžný status nejsou dostupné. [6][7]

Lze použít Access-Control-Allow-Origin: *?

Ano pro veřejné odpovědi bez credentials. Ne pro zpřístupnění odpovědí s credentials. [2][8][9]

Jak CORS funguje s cookies?

Frontend často používá credentials: "include", server musí vrátit konkrétní origin a Access-Control-Allow-Credentials: true. Cookie stále podléhá SameSite a Secure. [6][9][13]

Chrání CORS API před curl nebo boty?

Ne. CORS omezuje browser JavaScript. Klient mimo prohlížeč může poslat vlastní request i Origin, takže API stále potřebuje autorizaci. [16]

Chrání CORS proti CSRF?

Ne úplně. Cookie-based aplikace stále potřebují CSRF ochranu. [3][15][16]

Proč používat Vary: Origin?

Když se Access-Control-Allow-Origin mění dynamicky, Vary: Origin říká cache, že odpověď závisí na žádajícím originu. [1]

Jak snížit počet preflightů?

Výsledek lze cacheovat pomocí Access-Control-Max-Age nebo používat jednoduché requesty, pokud je to funkčně i bezpečnostně vhodné. [1][10][11]

Zdroje a reference

  1. MDN, Cross-Origin Resource Sharing (CORS)123456789101112131415
  2. WHATWG, Fetch Standard, CORS protocol123456789101112
  3. MDN, Same-origin policy123456
  4. MDN, Origin12
  5. MDN, Preflight request1234567
  6. MDN, Using the Fetch API12345678
  7. MDN, RequestInit12
  8. MDN, Access-Control-Allow-Origin123456
  9. MDN, Access-Control-Allow-Credentials123
  10. MDN, Access-Control-Max-Age1234
  11. MDN, CORS errors1234567
  12. MDN, CORS header Access-Control-Allow-Origin missing123
  13. MDN, Set-Cookie123
  14. MDN, Practical CORS configuration12
  15. MDN, Cross-site request forgery (CSRF)12
  16. OWASP, HTML5 Security Cheat Sheet, Cross Origin Resource Sharing123456789
  17. OWASP, HTTP Headers Cheat Sheet, Access-Control-Allow-Origin1234

Bylo to užitečné?

Odebírejte nové články e-mailem

Jeden krátký e-mail na každý nový článek znalostní báze. Žádný spam, odhlášení jedním kliknutím.

Váš e-mail používáme pouze k zasílání nových článků. Žádné sdílení s třetími stranami.

Zpět do znalostní báze