Co to jest CORS?
Autor: Redakcja Domeny.ForSale Opublikowano
W skrócie: CORS (Cross-Origin Resource Sharing) to mechanizm, dzięki któremu serwer może pozwolić przeglądarce na udostępnienie odpowiedzi skryptowi działającemu pod innym adresem pochodzenia. O zgodzie decydują nagłówki odpowiedzi serwera, a ich przestrzegania pilnuje przeglądarka. Błąd CORS zwykle oznacza więc problem z uprawnieniem do odczytu odpowiedzi, niekoniecznie brak połączenia z serwerem.
Dlaczego przeglądarka ogranicza dostęp między adresami
Przeglądarki stosują zasadę tego samego pochodzenia, czyli same-origin policy. Ogranicza ona możliwość odczytywania przez skrypt danych z innego pochodzenia. Dzięki temu strona otwarta w jednej karcie nie może swobodnie pobierać i odczytywać prywatnych danych z innych serwisów, w których użytkownik jest zalogowany.
Pochodzenie (origin) to zestaw trzech elementów: protokołu, nazwy hosta i portu. Zmiana choćby jednego z nich oznacza inne pochodzenie. Ścieżka po nazwie hosta nie ma tutaj znaczenia.
Dla strony https://sklep.example porównanie wygląda tak:
| Adres docelowy | To samo pochodzenie? | Powód |
|---|---|---|
https://sklep.example/produkty | Tak | Zmienia się tylko ścieżka |
https://api.sklep.example | Nie | Inna nazwa hosta |
http://sklep.example | Nie | Inny protokół |
https://sklep.example:8443 | Nie | Inny port niż domyślny 443 |
CORS pozwala serwerowi kontrolowanie poluzować tę zasadę. Nie jest metodą HTTP, taką jak GET lub POST, lecz mechanizmem opartym na nagłówkach HTTP.
Prosty przykład: sklep pobiera listę produktów
Załóżmy, że strona działa pod adresem https://sklep.example, a API, czyli interfejs udostępniający dane aplikacji, pod https://api.sklep.example. Skrypt strony chce pobrać produkty:
fetch('https://api.sklep.example/produkty')
.then(odpowiedz => odpowiedz.json())
.then(produkty => console.log(produkty));
Ponieważ adresy mają różne pochodzenie, przeglądarka dodaje do żądania nagłówek wskazujący pochodzenie strony:
Origin: https://sklep.example
Serwer API może odpowiedzieć danymi i nagłówkiem ze zgodą:
Access-Control-Allow-Origin: https://sklep.example
Przeglądarka porównuje tę wartość z pochodzeniem strony. Jeśli zgoda pasuje, udostępnia odpowiedź skryptowi. Jeśli nagłówka brakuje albo wskazuje inny adres, skrypt nie może odczytać odpowiedzi — nawet gdy serwer zwrócił status 200 OK.
Nagłówek ze zgodą musi pochodzić z serwera API. Dodanie Access-Control-Allow-Origin w kodzie żądania po stronie przeglądarki nie rozwiązuje problemu.
Kiedy przeglądarka najpierw wysyła OPTIONS
Nie każde żądanie między różnymi pochodzeniami jest wysyłane od razu. Przy niektórych przeglądarka najpierw wykonuje preflight, czyli zapytanie wstępne sprawdzające zgodę serwera.
Przykładowo wysłanie zamówienia metodą POST z typem treści application/json wywołuje taki etap. Podobnie działa użycie nagłówka Authorization. Zapytanie wstępne może wyglądać następująco:
OPTIONS /zamowienia HTTP/1.1
Origin: https://sklep.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Serwer powinien odpowiedzieć zgodą obejmującą pochodzenie, metodę i potrzebne nagłówki:
Access-Control-Allow-Origin: https://sklep.example
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type
Dopiero po udanym sprawdzeniu przeglądarka wysyła właściwy POST. Odpowiedź na ten POST również musi zawierać odpowiedni nagłówek Access-Control-Allow-Origin.
Nie każde żądanie POST wymaga preflight. Znaczenie mają także nagłówki i typ przesyłanej treści; zwykły GET bez dodatkowych nagłówków często nie potrzebuje zapytania wstępnego.
Cookies i gwiazdka: dwie ważne pułapki
Publiczne API, którego odpowiedzi mają być dostępne dla skryptów z dowolnego pochodzenia, może zwracać:
Access-Control-Allow-Origin: *
Gwiazdka nie jest jednak właściwym rozwiązaniem dla żądań wysyłanych z cookies w trybie uwzględniającym dane uwierzytelniające. W takim przypadku kod może używać credentials: 'include', a serwer musi wskazać konkretne dozwolone pochodzenie oraz zwrócić:
Access-Control-Allow-Origin: https://sklep.example
Access-Control-Allow-Credentials: true
Sama konfiguracja CORS nie gwarantuje przesłania cookies. Obowiązują również reguły cookies, między innymi SameSite, oraz ograniczenia prywatności przeglądarki.
Jeśli serwer obsługuje kilka zaufanych pochodzeń, powinien sprawdzać nagłówek Origin względem listy dozwolonych wartości. Bezrefleksyjne odsyłanie dowolnego otrzymanego pochodzenia ze zgodą na dane uwierzytelniające może ujawnić prywatne odpowiedzi. Przy odpowiedzi zależnej od Origin należy również zadbać o Vary: Origin, aby pamięć podręczna rozróżniała warianty odpowiedzi.
Jak diagnozować błąd CORS
W narzędziach deweloperskich przeglądarki otwórz kartę sieciową i wykonaj cztery sprawdzenia:
- Porównaj protokół, host i port strony oraz API.
- Sprawdź, czy występuje żądanie
OPTIONSi czy serwer poprawnie na nie odpowiada. - Obejrzyj nagłówki odpowiedzi właściwego żądania, także przy błędzie serwera.
- Sprawdź, czy zgoda obejmuje używaną metodę, nagłówki i ewentualne dane uwierzytelniające.
To, że wywołanie działa w curl, nie dowodzi poprawności CORS: takie narzędzie nie egzekwuje ograniczeń przeglądarki. Ustawienie mode: 'no-cors' również nie odblokuje odczytu JSON — daje odpowiedź nieprzezroczystą, której treść nie jest dostępna dla skryptu.
CORS nie zastępuje logowania, kontroli uprawnień ani ochrony przed CSRF, czyli wymuszaniem niechcianych działań przez inną stronę. Część żądań może dotrzeć do serwera mimo zablokowania odczytu odpowiedzi. Zacznij naprawę od konfiguracji API lub kontrolowanego pośrednika, a nie od wyłączania zabezpieczeń przeglądarki.
Zobacz też: Co to jest API?
