CORS w praktyce - jak działa i jak uniknąć błędów

Sylwia Szczepańska 18 sierpnia 2026
Laptop z czerwonym symbolem kłódki na ekranie, otoczony cyfrowym, futurystycznym obwodem. To wizualizacja bezpieczeństwa danych i ochrony przed cyberatakami.

Spis treści

Przeglądarka potrafi bezpiecznie odsiać żądania między różnymi domenami, ale ta ochrona bywa zaskakująca, zwłaszcza gdy frontend i API nie stoją w tym samym miejscu. Właśnie tu wchodzi CORS: mechanizm, który decyduje, czy JavaScript może odczytać odpowiedź z innej domeny, portu albo protokołu. Poniżej wyjaśniam, jak działa, kiedy pojawia się błąd i jak skonfigurować go tak, żeby nie psuł pracy aplikacji.

Najważniejsze informacje o CORS w praktyce

  • CORS działa po stronie przeglądarki i reguluje odczyt odpowiedzi z innego originu, a nie samą możliwość wysłania żądania.
  • Origin składa się z trzech elementów: protokołu, hosta i portu.
  • Przy bardziej złożonych żądaniach przeglądarka często wysyła najpierw zapytanie preflight metodą OPTIONS.
  • Najważniejsze nagłówki to m.in. `Access-Control-Allow-Origin`, `Access-Control-Allow-Methods`, `Access-Control-Allow-Headers` i `Access-Control-Allow-Credentials`.
  • Gwiazda `*` nie pasuje do scenariuszy z ciasteczkami lub autoryzacją opartą na credentialach.
  • CORS nie zastępuje ochrony przed CSRF ani nie rozwiązuje wszystkich problemów bezpieczeństwa aplikacji webowej.

Schemat ilustruje przepływ danych między przeglądarką (Domain A) a serwerem (Domain B), pokazując proces CORS i nagłówki CORS.

Jak przeglądarka sprawdza, czy może odczytać odpowiedź

Najprościej mówiąc, przeglądarka porównuje, skąd pochodzi strona uruchamiająca JavaScript i skąd ma przyjść odpowiedź. Jeśli protokół, domena lub port są inne, mamy do czynienia z innym originem, nawet jeśli adresy wyglądają podobnie. To dlatego `http://localhost:3000` i `http://localhost:8080` traktowane są jako dwa różne miejsca, choć obie usługi działają na tej samej maszynie.

W praktyce proces wygląda tak:

  1. Frontend wysyła żądanie do API albo innego zasobu.
  2. Przeglądarka dopisuje nagłówek `Origin`, żeby pokazać, skąd przyszło żądanie.
  3. Serwer odpowiada nagłówkami, które mówią, czy ten origin ma prawo odczytać odpowiedź.
  4. Jeśli reguły się zgadzają, JavaScript dostaje dostęp do danych. Jeśli nie, przeglądarka blokuje odczyt.

Ważna rzecz, którą często podkreślam studentom: żądanie może zostać wysłane, ale odpowiedź może być ukryta przed kodem w przeglądarce. To nie jest to samo co blokada sieciowa. Gdy zrozumiesz ten rozdział, łatwiej będzie przejść do nagłówków, które faktycznie decydują o wyniku.

Które nagłówki naprawdę mają znaczenie

Mechanizm nie opiera się na jednym przełączniku. To zestaw nagłówków, które muszą do siebie pasować, a czasem także do sposobu uwierzytelniania. Poniższa tabela pokazuje najważniejsze z nich i ich rolę w praktyce.

Nagłówek Do czego służy Na co uważać
`Origin` Informuje serwer, z jakiego originu przyszło żądanie. To nagłówek wysyłany przez przeglądarkę, a nie ręcznie przez frontend.
`Access-Control-Allow-Origin` Wskazuje, które originy mogą odczytać odpowiedź. Przy danych uwierzytelnionych zwykle trzeba podać konkretny origin, a nie `*`.
`Access-Control-Allow-Methods` Określa dozwolone metody, np. GET, POST, PUT lub DELETE. Musi pokrywać się z metodą używaną przez aplikację.
`Access-Control-Allow-Headers` Lista nagłówków, które przeglądarka może wysłać w właściwym żądaniu. Ma znaczenie zwłaszcza przy własnych nagłówkach, np. `Authorization`.
`Access-Control-Allow-Credentials` Sygnalizuje, że odpowiedź może być użyta razem z cookies lub innymi credentialami. Wymaga bardzo ostrożnej konfiguracji i nie działa dobrze z wildcardem.
`Vary: Origin` Pomaga cache'owi odróżnić odpowiedzi zależne od originu. Jest szczególnie ważny, gdy serwer dynamicznie zwraca różne originy.

Ja zwykle zaczynam od `Access-Control-Allow-Origin`, bo bez niego większość błędów pojawia się od razu. Jeśli jednak aplikacja korzysta z logowania, tokenów albo ciasteczek, trzeba sprawdzić także credentiale i spójność cache'a. To prowadzi prosto do preflightu, który dla wielu osób jest źródłem pierwszego zaskoczenia.

Kiedy pojawia się preflight i dlaczego nie trzeba się go bać

Preflight to dodatkowe sprawdzenie wykonywane przez przeglądarkę przed właściwym żądaniem. Najczęściej pojawia się wtedy, gdy wysyłasz metodę inną niż prosty GET lub POST, używasz własnych nagłówków albo deklarujesz typ danych, który wymaga dokładniejszej weryfikacji. Przeglądarka wysyła wtedy żądanie `OPTIONS`, a w nim pyta serwer, czy ten konkretny ruch jest dozwolony.

W tym zapytaniu pojawiają się między innymi:

  • `Access-Control-Request-Method`, czyli metoda, którą planuje użyć przeglądarka,
  • `Access-Control-Request-Headers`, czyli nagłówki, które mają trafić w kolejnym kroku,
  • `Origin`, czyli informacja o źródle żądania.

Jeśli serwer odpowie zgodnie z oczekiwaniami, przeglądarka przechodzi do właściwego żądania. Jeśli nie, zatrzymuje operację jeszcze przed dotarciem do API. To ważne, bo w logach backendu możesz widzieć tylko preflight, a nie widzieć samego requestu właściwego. Dla porządku warto też wiedzieć, że wynik preflightu może być buforowany, więc czasem zmiana konfiguracji nie od razu jest widoczna w testach.

Gdy ten etap jest ustawiony poprawnie, najczęstsze problemy nie znikają same. Zazwyczaj przenoszą się na poziom konfiguracji, a tam popełnia się kilka powtarzalnych błędów.

Najczęstsze błędy w konfiguracji api

W praktyce błędy CORS są dość przewidywalne, tylko komunikaty w konsoli potrafią być mało pomocne. Poniżej zebrałam sytuacje, które widzę najczęściej, razem z ich skutkami i sensowną reakcją.

Objaw Najbardziej prawdopodobna przyczyna Co zrobić
Żądanie działa w Postmanie, ale nie działa w przeglądarce Problem dotyczy tylko polityki przeglądarki, a nie samego API. Sprawdź nagłówki CORS, zamiast szukać błędu w logice endpointu.
Wszystko działa, dopóki nie dodasz logowania Credentiale wymagają bardziej rygorystycznej konfiguracji. Nie używaj `*` dla originu i sprawdź `Access-Control-Allow-Credentials`.
Preflight przechodzi, a właściwe żądanie już nie Serwer odpowiada innym zestawem nagłówków przy realnym requestcie. Ujednolić odpowiedzi dla OPTIONS i dla żądania właściwego.
Po wdrożeniu na produkcję cache zachowuje się dziwnie Brakuje `Vary: Origin` przy dynamicznym doborze dozwolonych originów. Dodaj ten nagłówek, żeby cache nie mieszał odpowiedzi.
Frontend z localhost działa tylko po części Port wciąż tworzy inny origin, choć adres wydaje się lokalny. Upewnij się, że backend dopuszcza dokładny origin developmentowy.

W takich sytuacjach nie szukam od razu skomplikowanej przyczyny. Najpierw sprawdzam, czy problem dotyczy originu, metod, nagłówków czy credentiali, bo to zwykle skraca diagnozę z godzin do minut. I właśnie tu przydaje się rozróżnienie między CORS a innymi mechanizmami bezpieczeństwa, które często wrzuca się do jednego worka.

Czym CORS różni się od same-origin policy, CSRF i innych zabezpieczeń

To jeden z punktów, który najczęściej powoduje nieporozumienia. CORS nie jest tym samym co sama polityka same-origin, nie zastępuje też ochrony przed CSRF i nie robi za uniwersalny firewall aplikacji webowej. Działa w węższym zakresie: pozwala przeglądarce zdecydować, czy kod JavaScript może odczytać odpowiedź z innego originu.

Mechanizm Co kontroluje Czego nie załatwia
Same-origin policy Domyślną blokadę dostępu między różnymi originami. Nie rozwiązuje problemu legalnych integracji z API z innej domeny.
CORS To, czy przeglądarka pozwoli odczytać odpowiedź z innego originu. Nie chroni samodzielnie przed fałszywymi żądaniami typu CSRF.
CSRF token lub SameSite cookies To, czy żądanie rzeczywiście pochodzi od zaufanej sesji i zaufanego kontekstu. Nie rozwiązuje problemu czytelności odpowiedzi przez frontend.
CSP Jakie zasoby strona może ładować i uruchamiać. Nie służy do zezwalania na odczyt danych z obcego API.
CORP Czy zasób ma być blokowany przy określonych cross-originowych żądaniach. Nie jest zamiennikiem CORS dla aplikacji pobierających dane z API.

Jeśli mam wskazać jedną praktyczną zasadę, to brzmi ona tak: CORS jest mechanizmem dostępu, a nie pełną strategią bezpieczeństwa. Gdy projekt wymaga logowania i modyfikacji danych, trzeba go łączyć z innymi zabezpieczeniami. To prowadzi do najważniejszego pytania: jak skonfigurować wyjątek tak, żeby był użyteczny, ale nie zbyt szeroki?

Jak ustawić bezpieczny wyjątek w projekcie

Najzdrowsze podejście to allowlista, a nie „wpuszczanie wszystkich”. W projekcie studenckim lub małym produkcyjnym najczęściej wystarczy jedna lub kilka zaufanych lokalizacji, na przykład frontend na osobnym subdomenowym adresie i API na innej usłudze. Wtedy serwer powinien zwracać tylko te originy, które naprawdę są potrzebne.

Przykład bezpieczniejszej konfiguracji odpowiedzi może wyglądać tak:

Access-Control-Allow-Origin: https://app.example.pl
Access-Control-Allow-Credentials: true
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: Content-Type, Authorization
Vary: Origin

W tym układzie ważne są trzy rzeczy. Po pierwsze, origin jest konkretny, a nie gwiazdkowy. Po drugie, credentiale są włączane tylko wtedy, gdy naprawdę ich potrzebujesz. Po trzecie, `Vary: Origin` chroni cache przed zwróceniem niewłaściwej odpowiedzi innemu klientowi.

W środowisku lokalnym polecam myśleć o porcie jak o pełnoprawnej części adresu bezpieczeństwa. Dla ucznia albo studenta to często jest najbardziej praktyczna lekcja: dwie usługi na `localhost` nadal mogą nie widzieć się nawzajem bez odpowiednich nagłówków. Gdy to zrozumiesz, dużo rzadziej trafiasz w ślepe konfiguracje i dużo szybciej odróżniasz problem po stronie frontendu od błędu po stronie serwera.

Krótka checklista, gdy aplikacja znowu wpada w błąd dostępu

Gdybym miała diagnozować problem bez zgadywania, szłabym zawsze tą samą kolejnością. Najpierw sprawdzam, czy frontend i backend mają ten sam protokół, host i port. Potem patrzę, czy serwer odpowiada na preflight tymi samymi regułami, które obowiązują dla właściwego żądania.

  • Sprawdź dokładny origin aplikacji, nie tylko samą domenę.
  • Zweryfikuj, czy preflight `OPTIONS` dostaje poprawne `Allow-Methods` i `Allow-Headers`.
  • Przy cookies i autoryzacji nie używaj `*` w `Access-Control-Allow-Origin`.
  • Dodaj `Vary: Origin`, jeśli origin jest dobierany dynamicznie.
  • Oddziel problem CORS od problemu CSRF, bo to dwa różne poziomy ochrony.
  • Testuj w przeglądarce, nie tylko w narzędziach typu curl czy Postman.

Jeśli trzymasz się tej kolejności, większość błędów przestaje być tajemnicą, a staje się zwykłą kwestią konfiguracji. I właśnie o to chodzi w CORS: nie o „blokadę dla bloku”, tylko o świadome sterowanie tym, co frontend może bezpiecznie odczytać.

FAQ - Najczęstsze pytania

Preflight pojawia się zwykle przy bardziej złożonych żądaniach, na przykład gdy używasz metody innej niż prosty GET lub POST, własnych nagłówków albo typu danych wymagającego dokładniejszej weryfikacji. Przeglądarka pyta wtedy serwer w żądaniu OPTIONS, czy dany ruch jest dozwolony, zanim wyśle właściwe żądanie.

Gdy aplikacja korzysta z credentiali, potrzebujesz bardziej rygorystycznej konfiguracji niż wildcard. W takim przypadku serwer powinien zwracać konkretny origin, a nie `*`, i odpowiednio ustawić `Access-Control-Allow-Credentials`.

Same-origin policy to domyślna blokada dostępu między różnymi originami, a CORS mówi przeglądarce, czy może odczytać odpowiedź z innego originu. CSRF to osobny problem, więc CORS nie zastępuje tokenów CSRF ani zabezpieczeń opartych na SameSite cookies.

Najpierw upewnij się, że protokół, host i port są zgodne, bo `http://localhost:3000` i `http://localhost:8080` to dwa różne originy. Potem sprawdź, czy backend dopuszcza dokładny origin z developmentu oraz czy preflight i właściwe żądanie dostają spójne nagłówki.

Jest to ważne wtedy, gdy serwer dynamicznie zwraca różne dozwolone originy. Taki nagłówek pomaga cache'owi odróżnić odpowiedzi i zapobiega sytuacji, w której jedna wersja nagłówków zostanie omyłkowo podana innemu klientowi.

Oceń artykuł

Ocena: 0.00 Liczba głosów: 0

Tagi

cors
origin
preflight
csrf
samesite
Autor Sylwia Szczepańska
Sylwia Szczepańska
Nazywam się Sylwia Szczepańska i od 4 lat zajmuję się tematyką edukacji oraz rozwoju osobistego. Moje zainteresowanie tymi dziedzinami zaczęło się od chęci zrozumienia, jak możemy lepiej uczyć się i rozwijać w dzisiejszym świecie, pełnym informacji. Staram się dzielić wiedzą na temat efektywnych metod nauki, zarządzania czasem oraz osobistego rozwoju, aby pomóc innym w osiąganiu ich celów. Pisząc, koncentruję się na dostarczaniu użytecznych, dokładnych i przystępnych informacji. Zawsze sprawdzam źródła, porównuję różne podejścia i staram się upraszczać skomplikowane tematy, aby były zrozumiałe dla każdego. Uwielbiam śledzić najnowsze trendy w edukacji i organizować wiedzę w sposób, który ułatwia jej przyswajanie. Moim celem jest inspirowanie innych do ciągłego rozwoju i poszerzania horyzontów.

Udostępnij artykuł

Napisz komentarz