CORS: čo je a prečo prehliadač blokuje API | POLPROG Prejsť na obsah

CORS: čo je a prečo prehliadač blokuje API

CORS nie je mechanizmus, ktorý jednoducho blokuje spojenia s API. Je to protokol prehliadača postavený na same-origin policy, ktorý rozhoduje, či JavaScript z jedného originu môže čítať odpoveď z iného originu. V niektorých prípadoch sa HTTP request odošle a prehliadač iba zablokuje prístup skriptu k odpovedi. V iných prípadoch najprv odošle preflight OPTIONS a podľa výsledku rozhodne, či sa skutočný request vôbec odošle.

Publikované Autor Čas čítania 19 min čítania

CORS nie je mechanizmus, ktorý jednoducho blokuje spojenia s API. Je to protokol prehliadača postavený na same-origin policy, ktorý rozhoduje, či JavaScript z jedného originu môže čítať odpoveď z iného originu. V niektorých prípadoch sa HTTP request odošle a prehliadač iba zablokuje prístup skriptu k odpovedi. V iných prípadoch najprv odošle preflight OPTIONS a podľa výsledku rozhodne, či sa skutočný request vôbec odošle.

Na tejto stránke
  1. 1CORS začína pri same-origin policy
  2. 2Čo presne znamená origin
  3. 3Čo naozaj znamená, že prehliadač blokuje API
  4. 4Jednoduché requesty: kedy sa preflight nepoužije
  5. 5Preflight OPTIONS: čo prehliadač overuje
  6. 6Najdôležitejšie CORS headers
  7. 7`Access-Control-Allow-Origin`: wildcard alebo konkrétny origin
  8. 8Cookies a credentials: častý zdroj problémov
  9. 9Prečo `mode: "no-cors"` zvyčajne nič neopraví
  10. 10Prečo curl, Postman alebo backend môžu fungovať
  11. 11CORS nenahrádza CSRF ochranu ani autorizáciu
  12. 12Časté chyby a diagnostika
  13. 13Nebezpečné CORS konfigurácie
  14. 14Výkon: cena preflightu a `Access-Control-Max-Age`
  15. 15Praktická konfigurácia a checklist nasadenia

CORS začína pri same-origin policy

Same-origin policy je základný bezpečnostný mechanizmus prehliadača. Obmedzuje možnosť dokumentu alebo skriptu čítať dáta z iného originu a bráni napríklad škodlivej stránke čítať dáta zo služby, kde je používateľ prihlásený. [3]

CORS, Cross-Origin Resource Sharing, je HTTP mechanizmus, ktorým server túto zásadu kontrolovane uvoľňuje a určuje, ktoré originy môžu odpoveď čítať. Fetch Standard ho opisuje ako opt-in protokol. [1][2]

Čo presne znamená origin

StránkaCieľová URLVzťahPrečo
https://app.example.comhttps://app.example.com/apiRovnaký originRovnaká schéma, host a port
https://app.example.comhttps://api.example.comIný originIný host
https://app.example.comhttp://app.example.comIný originIná schéma
https://app.example.comhttps://app.example.com:8443Iný originIný port
https://app.example.comhttps://app.example.com/v2Rovnaký originMení sa iba cesta

Origin je daný schémou, hostom a portom. Dve URL sú same-origin iba vtedy, keď sa zhodujú všetky tri hodnoty. Cesta nehrá úlohu. [3][4]

`https://app.example.com` a `https://api.example.com` sú teda rôzne originy. Rovnako HTTP a HTTPS alebo rozdielne porty. [4]

Same-origin a same-site nie sú totožné pojmy. Je to dôležité pri cookies, pretože `SameSite` používa pojem site, zatiaľ čo CORS používa origin. [13]

Čo naozaj znamená, že prehliadač blokuje API

Tvrdenie, že prehliadač blokuje request, je často príliš zjednodušené. Pri jednoduchom cross-origin requeste môže request odoslať, prijať platnú HTTP odpoveď a až potom ju nesprístupniť JavaScriptu, ak CORS kontrola zlyhá. [1][6]

Pri requestoch s preflightom je priebeh iný. Najprv sa posiela `OPTIONS`. Ak preflight zlyhá, skutočný request sa neodošle. [2][5][6]

Tento rozdiel je dôležitý pri operáciách meniacich dáta. CORS chyba automaticky neznamená, že backend žiadny request nedostal.

Jednoduché requesty: kedy sa preflight nepoužije

MetódaPríklad headersJednoduchý requestDôsledok
GETAcceptÁnoBez preflightu
POSTContent-Type: text/plainÁnoBez preflightu
POSTContent-Type: application/jsonNieJSON vyvolá preflight
PUTContent-Type: application/jsonNieMetóda vyvolá preflight
GETAuthorization: Bearer ...NieHeader vyvolá preflight

Request je jednoduchý iba pri splnení CORS safelist. Povolené metódy sú `GET`, `HEAD` a `POST`. Ručne nastavené headers musia byť safelisted a `Content-Type` smie byť iba `application/x-www-form-urlencoded`, `multipart/form-data` alebo `text/plain`. [1]

Bežný `POST` s `Content-Type: application/json` nie je jednoduchý a zvyčajne vyvolá preflight. Rovnako `PUT`, `DELETE` alebo vlastný header typu `X-Request-ID`. [1][11]

Preflight OPTIONS: čo prehliadač overuje

Preflight je automatický `OPTIONS` request. Prehliadač posiela `Origin`, `Access-Control-Request-Method` a podľa potreby `Access-Control-Request-Headers`. Server odpovie povolenými originmi, metódami a headers. [2][5]

Ak chce aplikácia poslať `DELETE` s `Authorization`, prehliadač môže najprv overiť, či daný origin smie použiť túto metódu a header. Až kladná odpoveď dovolí skutočný request. [5]

Preflight pridáva ďalší sieťový round trip, ale výsledok možno uložiť do samostatnej CORS preflight cache mimo bežnej HTTP cache. [5][10]

Najdôležitejšie CORS headers

HeaderSmerÚčel
OriginRequestOrigin, ktorý request iniciuje
Access-Control-Allow-OriginResponseOrigin, ktorého kód môže odpoveď dostať
Access-Control-Allow-MethodsPreflight responseMetódy povolené preflightom
Access-Control-Allow-HeadersPreflight responseRequest headers povolené preflightom
Access-Control-Allow-CredentialsResponsePovolenie sprístupniť odpoveď s credentials
Access-Control-Expose-HeadersResponseĎalšie response headers dostupné JavaScriptu
Access-Control-Max-AgePreflight responseDoba cache výsledku preflightu
Vary: OriginResponseInformácia pre cache, že odpoveď závisí od Origin

`Origin` je request header označujúci iniciujúci origin. `Access-Control-Allow-Origin` je serverový response header, ktorý hovorí prehliadaču, či môže odpoveď zdieľať s kódom z daného originu. [1][2][8]

`Access-Control-Allow-Methods` a `Access-Control-Allow-Headers` sú dôležité najmä pri preflighte. `Access-Control-Allow-Credentials` povoľuje sprístupnenie odpovede s credentials a `Access-Control-Expose-Headers` sprístupní JavaScriptu ďalšie response headers. [1][2]

Ak server nastavuje `Access-Control-Allow-Origin` dynamicky, MDN odporúča aj `Vary: Origin`. [1]

`Access-Control-Allow-Origin`: wildcard alebo konkrétny origin

`Access-Control-Allow-Origin: *` povoľuje zdieľanie odpovede s ľubovoľným originom pri requestoch bez credentials. Pre skutočne verejné API to môže byť správne. [2][8]

Pri privátnych alebo citlivých endpointoch by mala byť povolená množina čo najmenšia. MDN a OWASP odporúčajú konkrétne originy, ak nie je globálny prístup potrebný. [14][17]

Pri viacerých povolených originoch má server porovnať prichádzajúci `Origin` s allowlistom a vrátiť iba schválenú hodnotu. Slepé zrkadlenie ľubovoľného originu je nebezpečné. [8][16]

Cookies a credentials: častý zdroj problémov

Fetch môže použiť `credentials: "include"` pre credentials v cross-origin requests. To samo nestačí. Server musí vrátiť `Access-Control-Allow-Credentials: true` a konkrétny `Access-Control-Allow-Origin`. `*` tu nie je povolené. [2][6][9]

Cookies podliehajú aj vlastným pravidlám. `SameSite` môže zabrániť ich odoslaniu pri cross-site requeste a `SameSite=None` vyžaduje `Secure`. [13]

CORS a `SameSite` riešia odlišné problémy. CORS môže byť správne, ale cookie chýba, alebo cookie môže odísť a CORS stále zablokuje JavaScriptu odpoveď.

Prečo `mode: "no-cors"` zvyčajne nič neopraví

`fetch(..., { mode: "no-cors" })` neobchádza CORS, ak aplikácia potrebuje odpoveď čítať. Metódy a headers sú obmedzené a odpoveď je opaque. JavaScript nemôže čítať body ani headers a viditeľný status je `0`. [6][7][11]

`no-cors` má špecializované použitie, napríklad niektoré scenáre Service Worker, ale pre bežné JSON API je zvyčajne zlou voľbou. [6]

Ak externé API CORS neponúka, vlastný backend alebo proxy môže vykonať request server-to-server. [11][12]

Prečo curl, Postman alebo backend môžu fungovať

Same-origin policy a CORS vynucuje prehliadač. HTTP klient mimo tohto modelu rovnakou CORS kontrolou neprechádza. Preto môže endpoint fungovať v curl alebo API nástroji a z JavaScriptu stránky byť blokovaný. [2][3][16]

To tiež ukazuje, prečo CORS nie je autentizácia API. Klient mimo prehliadača môže nastaviť vlastný `Origin`, takže OWASP varuje pred použitím tohto headeru ako dôkazu identity. [16]

API stále potrebuje autorizáciu, tokeny, sessions, kontroly oprávnení a serverovú validáciu.

CORS nenahrádza CSRF ochranu ani autorizáciu

Same-origin policy obmedzuje najmä cross-origin čítanie. Formuláre a niektoré jednoduché requesty možno napriek tomu posielať cross-origin, takže cookie-based aplikácie stále potrebujú CSRF ochranu. [3][15]

OWASP výslovne odporúča nespoliehať sa iba na CORS alebo `Origin` pri ochrane citlivých zdrojov. Autentizácia a autorizácia sú potrebné nezávisle. [16]

CORS odpovedá na otázku, či prehliadač môže sprístupniť odpoveď kódu z originu. Nerieši, či používateľ alebo klient smie operáciu vykonať.

Časté chyby a diagnostika

Chýbajúci `Access-Control-Allow-Origin` je bežná chyba. Ďalšie príčiny sú nepovolená metóda, chýbajúca položka v `Access-Control-Allow-Headers`, `*` s credentials, chybná OPTIONS odpoveď alebo redirecty v CORS flow. [11][12]

JavaScript dostáva zámerne iba obmedzené detaily. Pre presnú diagnostiku je dôležitejšia konzola a Network panel. [1][11]

`CORS request did not succeed` môže spôsobiť aj DNS, timeout, odmietnuté spojenie, TLS, mixed content alebo browser extension. [11]

  • Skontrolujte presný frontend origin: schéma, host a port.
  • Skontrolujte `OPTIONS`, ak existuje.
  • Overte status a `Access-Control-Allow-*` preflight odpovede.
  • Overte, že aj skutočná odpoveď obsahuje požadované CORS headers.
  • Pri cookies skontrolujte `credentials`, `Access-Control-Allow-Credentials`, `SameSite` a `Secure`.
  • Skontrolujte redirecty, TLS, mixed content a sieťové chyby.
  • Porovnajte browser request s fungujúcim curl alebo API-tool requestom.

Nebezpečné CORS konfigurácie

Slepé vracanie prichádzajúceho `Origin` je nebezpečné, ak requesty s credentials vracajú citlivé dáta. Útočník môže ovládať vlastný origin a pokúsiť sa čítať odpovede v kontexte prihláseného používateľa. [16]

Príliš široké regulárne výrazy a dôvera všetkým subdoménam sú tiež rizikové, ak možno niektorú subdoménu prevziať. OWASP odporúča presný allowlist. [16][17]

`Access-Control-Allow-Origin: *` nie je automaticky zraniteľnosť pri úplne verejných dátach bez credentials. Problémom je politika širšia, než je skutočne potrebné. [8][17]

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

Preflight pridáva pred skutočný request ďalší `OPTIONS` a môže zvýšiť latenciu. Jeho výsledok možno cacheovať pomocou `Access-Control-Max-Age` v samostatnej preflight cache. [5][10]

MDN uvádza bez headeru predvolenú hodnotu 5 sekúnd. Prehliadače majú vlastné maximá. Firefox obmedzuje na 86400 sekúnd a Chromium od verzie 76 na 7200 sekúnd. [10]

Stabilné politiky možno cacheovať, ale nie tak dlho, aby bolo ťažké rýchlo odvolať omylom príliš široké povolenie.

Praktická konfigurácia a checklist nasadenia

Najprv rozhodnite, či endpoint má byť vôbec dostupný cross-origin. Ak nie, CORS headers nepridávajte. Ak áno, definujte allowlist originov, potrebné metódy a headers a potrebu credentials. [14][17]

Pri dynamickom allowliste vráťte iba overený origin a pridajte `Vary: Origin`. S credentials používajte konkrétny origin a `Access-Control-Allow-Credentials: true`. Frontend toto serverové rozhodnutie nemôže nahradiť. [1][2]

Po nasadení otestujte jednoduchý request, preflight, scenár s cookie, nepovolený origin a skutočné chyby v DevTools.

  • Je cross-origin prístup naozaj potrebný?
  • Ktoré presné originy majú byť povolené?
  • Sú potrebné credentials?
  • Ktoré metódy a request headers sú potrebné?
  • Dostane sa `OPTIONS` do aplikácie a odpovie správne?
  • Obsahuje skutočná odpoveď správne CORS headers?
  • Obsahujú dynamické odpovede `Vary: Origin`?
  • Vyžaduje endpoint stále bežnú autentizáciu a autorizáciu?
  • Bola politika otestovaná s povoleným aj nepovoleným originom?

CORS treba chápať ako pravidlo prehliadača pre sprístupnenie odpovedí, nie ako univerzálnu bezpečnostnú hranicu API. Najprv určte origin frontendu a API, potom zistite, či je request jednoduchý alebo potrebuje preflight, a nakoniec skontrolujte OPTIONS a CORS headers skutočnej odpovede. Bezpečná konfigurácia povoľuje iba potrebné originy, metódy a headers, zatiaľ čo autentizácia a autorizácia zostávajú v aplikačnej vrstve.

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

Často kladené otázky

Čo je CORS?

CORS je HTTP protokol používaný prehliadačmi na riadené zdieľanie odpovedí medzi rôznymi originmi. Server pomocou headers určuje, ktoré originy môžu odpoveď čítať. [1][2]

Prečo API funguje v Postmane, ale nie v prehliadači?

Pretože CORS vynucuje prehliadač ako súčasť same-origin policy. HTTP klienti mimo prehliadača rovnakému mechanizmu nepodliehajú. [2][3][16]

Blokuje CORS vždy odoslanie requestu?

Nie. Jednoduchý request môže byť odoslaný a browser iba zablokuje JavaScriptu čítanie odpovede. Keď zlyhá povinný preflight, skutočný request sa neodošle. [1][5][6]

Čo spúšťa preflight?

Napríklad metódy mimo GET, HEAD, POST, vlastné headers alebo Content-Type: application/json. Prehliadač najprv posiela OPTIONS. [1][5]

Patrí Access-Control-Allow-Origin do frontendu?

Nie. Je to serverový response header. Frontend si týmto headerom nemôže sám udeliť oprávnenie. [1][8][12]

Opraví mode: "no-cors" CORS?

Nie pri bežnom API, ktorého dáta potrebujete čítať. Odpoveď je opaque a body, headers ani bežný status nie sú dostupné. [6][7]

Možno použiť Access-Control-Allow-Origin: *?

Áno pre verejné odpovede bez credentials. Nie pre sprístupnenie odpovedí s credentials. [2][8][9]

Ako CORS funguje s cookies?

Frontend často používa credentials: "include", server musí vrátiť konkrétny origin a Access-Control-Allow-Credentials: true. Cookie stále podlieha SameSite a Secure. [6][9][13]

Chráni CORS API pred curl alebo botmi?

Nie. CORS obmedzuje browser JavaScript. Klient mimo prehliadača môže poslať vlastný request aj Origin, takže API stále potrebuje autorizáciu. [16]

Chráni CORS proti CSRF?

Nie úplne. Cookie-based aplikácie stále potrebujú CSRF ochranu. [3][15][16]

Prečo používať Vary: Origin?

Keď sa Access-Control-Allow-Origin mení dynamicky, Vary: Origin hovorí cache, že odpoveď závisí od žiadajúceho originu. [1]

Ako znížiť počet preflightov?

Výsledok možno cacheovať pomocou Access-Control-Max-Age alebo používať jednoduché requesty, ak je to funkčne aj bezpečnostne vhodné. [1][10][11]

Zdroje a referencie

  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

Bolo to užitočné?

Získavajte nové články e-mailom

Jeden krátky e-mail na každý nový článok Vzdelávania. Žiadny spam, odhlásenie jedným kliknutím.

Váš e-mail používame len na zasielanie nových článkov. Žiadne zdieľanie s tretími stranami.

Späť na Vzdelávanie