CORS to mechanizm bezpieczeństwa przeglądarki, który pozwala stronie pobierać zasoby z innej domeny tylko wtedy, gdy serwer wyraźnie na to pozwala. W praktyce temat wraca przy integracjach z API, panelach administracyjnych i środowiskach testowych, a czasem problem nie leży w samej konfiguracji nagłówków, lecz w antywirusie, który filtruje ruch HTTPS. Poniżej rozkładam to na czynniki pierwsze: jak działa mechanizm, jak odróżnić błąd serwera od ingerencji lokalnej i co zrobić, żeby naprawić problem bez wyłączania ochrony na stałe.
Co warto wiedzieć o CORS i wpływie antywirusa
- CORS nie jest ustawieniem antywirusa, tylko regułą przeglądarki i serwera.
- Żądania cross-origin mogą wymagać preflightu `OPTIONS` i odpowiednich nagłówków odpowiedzi.
- Antywirus z funkcją `HTTPS scanning` potrafi zmienić zachowanie przeglądarki i wyglądać jak błąd CORS.
- Jeśli widzisz błąd certyfikatu, DNS, timeout lub TLS, najpierw sprawdź warstwę sieci, nie sam nagłówek `Access-Control-Allow-Origin`.
- Bezpieczna konfiguracja zwykle polega na dopuszczaniu konkretnych originów, a nie na otwieraniu wszystkiego przez `*`.
- Na komputerze firmowym nie wyłączaj ochrony na stałe bez zgody administratora.
Czym jest CORS i co dokładnie kontroluje
Jak podaje MDN, CORS opiera się na nagłówkach HTTP i pozwala serwerowi wskazać, z jakich originów przeglądarka może pobierać dane. Origin to nie tylko domena, ale też protokół i port, więc `http://localhost:3000` i `http://localhost:8080` to już dwa różne źródła. To dlatego front-end uruchomiony lokalnie tak często "nie widzi" API, mimo że technicznie oba komponenty należą do tego samego projektu.
Najważniejsze jest to, że przeglądarka sama z siebie nie udostępnia odpowiedzi kodowi JavaScript. Najpierw sprawdza, czy żądanie jest proste, a jeśli nie, wysyła preflight, czyli zapytanie `OPTIONS`, żeby zobaczyć, czy serwer akceptuje metodę, nagłówki i pochodzenie żądania. W praktyce oznacza to, że błąd może pojawić się jeszcze przed właściwym requestem.
- `GET`, `HEAD` i część `POST` zwykle przechodzą bez dodatkowego preflightu.
- `PUT`, `DELETE` i niestandardowe nagłówki częściej uruchamiają kontrolne `OPTIONS`.
- Jeśli odpowiedź nie ma właściwych nagłówków, przeglądarka blokuje dostęp mimo tego, że serwer "odpowiedział".
To rozróżnienie jest ważne, bo od niego zaczyna się sensowna diagnostyka. Gdy już wiadomo, co robi przeglądarka, łatwiej ocenić, kiedy winny jest serwer, a kiedy warstwa bezpieczeństwa po stronie użytkownika.

Dlaczego antywirus potrafi wyglądać jak problem CORS
W dokumentacji Avast funkcja `HTTPS scanning` służy do skanowania zaszyfrowanych połączeń. To brzmi niewinnie, ale technicznie oznacza, że pakiet bezpieczeństwa może pośredniczyć w ruchu TLS, sprawdzać treść i dopiero potem przekazywać ją dalej. Jeśli coś w tym łańcuchu się wysypie, przeglądarka często pokazuje objaw podobny do błędu CORS, choć źródło kłopotu leży niżej, w certyfikatach, inspekcji ruchu albo filtrze sieciowym.
Ja patrzę na to tak: CORS decyduje, czy aplikacja ma prawo przeczytać odpowiedź, a antywirus może sprawić, że sama odpowiedź nie dotrze w poprawnej formie. To dwa różne poziomy problemu. W jednym scenariuszu serwer zapomniał o nagłówku `Access-Control-Allow-Origin`, w drugim lokalne oprogramowanie bezpieczeństwa zmienia zachowanie połączenia i wywołuje efekt uboczny, który przypomina blokadę z przeglądarki.
Najczęściej widać to w trzech sytuacjach: przy lokalnym środowisku developerskim z własnym certyfikatem, przy VPN-ach i filtrach firmowych oraz przy pakietach bezpieczeństwa, które mają moduł Web Shield, SSL scanning albo podobny mechanizm. To zwykle dotyczy właśnie tych rozwiązań, które inspekcję robią na poziomie ruchu WWW, a nie prostego skanowania plików.
To prowadzi do prostego pytania: jak odróżnić prawdziwy błąd konfiguracji od lokalnego filtra, zanim zaczniemy przestawiać połowę ustawień przeglądarki.
Jak odróżnić błąd API od ingerencji lokalnej
W praktyce zaczynam od objawów, nie od zgadywania. MDN zwraca uwagę, że przy komunikacie typu `CORS request did not succeed` trzeba zaglądać do DevTools > Network, bo przyczyną może być DNS, timeout, odmowa połączenia albo błąd TLS. To jest ważne, bo taki komunikat wygląda jak polityka CORS, ale często wcale nią nie jest.
| Objaw | Bardziej prawdopodobna przyczyna | Co sprawdzić najpierw |
|---|---|---|
| Brakuje `Access-Control-Allow-Origin` w odpowiedzi | Konfiguracja API lub reverse proxy | Odpowiedź serwera dla właściwego originu i nagłówków |
| Pojawia się błąd certyfikatu, prywatnego połączenia albo TLS handshake | `HTTPS scanning`, proxy, problem z certyfikatem | Wyłącz na próbę samo skanowanie HTTPS lub sprawdź certyfikat |
| Żądanie działa na innym komputerze lub w innej sieci | Problem lokalny | Rozszerzenia przeglądarki, antywirus, firewall, VPN |
| W DevTools widać, że preflight `OPTIONS` nie dochodzi do skutku | Sieć, filtr, blokada pośrednia | Zakładka Network, status połączenia, logi ochrony |
| Po wyłączeniu Web Shield problem znika | Moduł inspekcji ruchu powoduje konflikt | Ustawienie `HTTPS scanning` i ewentualne wyjątki |
Ta tabela oszczędza czas, bo od razu pokazuje, gdzie szukać. Jeśli widzisz nagłówki CORS, ale jednocześnie masz problem z certyfikatem lub połączeniem, ja nie zaczynam od backendu. Najpierw sprawdzam warstwę lokalną, bo tam najczęściej kryje się fałszywy trop.
Co sprawdzić krok po kroku, zanim zmienisz ustawienia bezpieczeństwa
W takich przypadkach wolę iść krótką, powtarzalną ścieżką. Ona zwykle pokazuje winowajcę szybciej niż losowe wyłączanie kolejnych funkcji.
- Otwórz DevTools i odtwórz problem w zakładkach Console oraz Network.
- Sprawdź, czy widać preflight `OPTIONS` i jaką odpowiedź zwraca serwer.
- Uruchom stronę w trybie prywatnym albo w czystym profilu bez rozszerzeń.
- Na próbę wyłącz tylko moduł skanowania HTTPS/Web Shield, nie całą ochronę.
- Powtórz test na innej sieci lub bez VPN, jeśli z niego korzystasz.
- Jeśli błąd znika po jednym z tych testów, zapisz dokładnie, który mechanizm go wywołał.
Jeżeli problem znika dopiero po wyłączeniu filtra HTTPS, masz mocny sygnał, że to nie jest czysty CORS, tylko konflikt na poziomie transportu. Wtedy sensowniejsze staje się dodanie wyjątku albo poprawa certyfikatu niż grzebanie w nagłówkach API na ślepo.
Jeśli jednak żądanie przechodzi dalej, ale odpowiedź jest odrzucana, trzeba spojrzeć na konfigurację samego serwera.
Jak ustawić bezpieczny CORS w API
Najmniej problemów daje konfiguracja oparta na białej liście originów. Dla publicznego, nieuprzywilejowanego zasobu można użyć `Access-Control-Allow-Origin: *`, ale jeśli w grę wchodzą cookies albo tokeny uwierzytelniające, to już za mało i często jest to wręcz zły wybór. Wtedy serwer powinien zwracać konkretny origin, a przy dynamicznym dopasowaniu warto dodać też `Vary: Origin`, żeby cache nie mieszał odpowiedzi między różnymi źródłami.
| Scenariusz | Bezpieczny kierunek | Czego unikać |
|---|---|---|
| Publiczne API bez danych użytkownika | Jeden lub kilka jawnie dopuszczonych originów, ewentualnie `*` | Przypadkowe otwarcie całej domeny z danymi prywatnymi |
| API z cookies lub nagłówkami autoryzacji | Konkretny origin, `Access-Control-Allow-Credentials: true`, `Vary: Origin` | `*` przy credentialach |
| Wiele front-endów w organizacji | Allowlista sprawdzana po stronie serwera | Ręczne kopiowanie reguł do każdego środowiska bez kontroli |
| Środowisko testowe | Oddzielna konfiguracja dla dev/stage/prod | Przenoszenie testowych wyjątków do produkcji |
Ja zwracam też uwagę na nagłówki metody i pól, bo preflight jest bardzo literalny: jeśli frontend wysyła niestandardowy nagłówek albo metodę `DELETE`, backend musi to jawnie zaakceptować. To samo dotyczy przekierowań, bo CORS nie lubi nieprzemyślanych redirectów między originami.
Dobrze skonfigurowany CORS nie jest "bardziej otwarty" niż trzeba. Jest po prostu precyzyjny. I to jest różnica, która w praktyce robi większe wrażenie niż luźne ustawienie wszystkiego na `*`.
Najczęstsze błędy, które każą szukać winy nie tam, gdzie trzeba
W zespołach widzę kilka powtarzalnych pomyłek. Żadna z nich nie jest spektakularna, ale każda potrafi zabrać godzinę lub dwie.
- Mylenie błędu certyfikatu z błędem CORS. Jeśli HTTPS nie jest zaufany, przeglądarka może nie dojść nawet do etapu sprawdzania nagłówków.
- Wyłączanie całego antywirusa zamiast jednego modułu testowego. To niepotrzebne ryzyko, zwłaszcza na komputerze firmowym.
- Zapominanie, że inny port, protokół lub subdomena to inny origin.
- Sprawdzanie tylko głównego requestu i pomijanie preflight `OPTIONS`.
- Dodawanie zbyt szerokich wyjątków do produkcji, bo "na razie działa".
- Mylenie CORS z CSP albo CORP. To pokrewne mechanizmy bezpieczeństwa, ale rozwiązują inne problemy.
Jeśli miałbym wskazać jedną rzecz, która najczęściej psuje diagnozę, byłoby to zbyt szybkie założenie, że komunikat z konsoli musi oznaczać błąd po stronie API. Czasem jest odwrotnie: API jest poprawne, a problem robi lokalna inspekcja ruchu albo filtr sieciowy.
To właśnie dlatego zamykam temat krótką, praktyczną checklistą do wykorzystania przy kolejnym incydencie.
Co robię, żeby taki problem nie wracał przy następnym wdrożeniu
Najlepsza oszczędność czasu to nie "zapamiętać, że kiedyś coś wyłączyłem", tylko spisać, co dokładnie było sprawdzane: przeglądarka, adres, status preflightu, nagłówki odpowiedzi i ustawienie `HTTPS scanning`. Taki zapis pozwala odróżnić jednorazowy incydent od powtarzalnego wzorca.
W środowiskach firmowych dobrze działa osobny profil do testów, oddzielna lista dozwolonych originów i jasna zasada, że wyjątki w antywirusie są tymczasowe. W aplikacjach produkcyjnych wolę też prostą regułę: tylko te originy, które naprawdę muszą mieć dostęp, a reszta bez wyjątków. To mniej efektowne niż "otwarcie wszystkiego", ale dużo stabilniejsze i bezpieczniejsze.
Jeżeli po tej diagnostyce dalej widzisz konflikt, zacznij od sprawdzenia odpowiedzi `OPTIONS`, certyfikatu i modułów ochrony webowej. Gdy rozdzielisz warstwę przeglądarki, serwera i antywirusa, problem zwykle przestaje być tajemnicą i staje się zwykłą usterką do naprawienia.