CORS od podszewki – poradnik dla webdeveloperów ze wszystkimi szczegółami
Ocena: 5 - 1 głosów

Dzisiejszy przewodnik skierowany jest do wszystkich programistów, którzy zajmują się aplikacjami webowymi. Myślę, że jest to pozycja obowiązkowa zarówno dla ludzi, którzy tworzą API jak i front-end. Jeśli jeszcze nie spotkałeś(aś) się z terminem CORS, to zapewne niedługo się to wydarzy. Aby Twoja wiedza nie ograniczała się jedynie do „trzeba dodać nagłówek na backendzie” – zachęcam do lektury. Postaram się wytłumaczyć wszystko „na chłopski rozum”, ale zdaję sobie sprawę z tego, że temat może wydawać się trudny dla początkujących. Każde trudniejsze zagadnienie będzie okraszone odnośnikiem do zewnętrznego źródła wiedzy, które powinno rozwiać wątpliwości.

Po co to?

Od tego należałoby zacząć. Twórcy przeglądarek internetowych też dbają o bezpieczeństwo swoich użytkowników. Żyjemy w świecie, w którym zostając w domu możemy zrobić zakupy czy wykonać przelew bankowy. CORS jest mechanizmem, który ma za zadanie ograniczyć dostęp do zasobów dostępnych poza naszą domeną. Z założenia chodzi o utrudnienie ataków typu CSRF. Będąc administratorem strony internetowej niejako odpowiadamy za bezpieczeństwo naszych użytkowników. Jest to więc nie tylko dodatkowa bolączka, ale także ukłon w stronę webdeveloperów ze strony twórców przeglądarek. Blokada ta nie odnosi się do obrazków, plików css, js, video. Dlatego możemy bez problemu wrzucić zdjęcie, które zamieszczone jest na innym serwerze czy podpiąć bibliotekę serwowaną z CDN. Chodzi przede wszystkim o zapytania HTTP realizowane przez XMLHttpRequest, ale trzeba pamiętać też o fontach wczytywanych przez @font-face czy o obrazach ładowanych do canvas. Oczywiście możemy zezwolić na takie połączenia ze zdalnym serwerem, np. gdy nasze API stoi na innej maszynie. O tym za chwilę.

Kiedy przeglądarka korzysta z CORS?

  • inna domena (np. strona przyklad.pl łączy się z api.pl)
  • inna subdomena (np. strona web.przyklad.pl łączy się z api.przyklad.pl)
  • inny port (np. strona przyklad.pl łączy się z przyklad.pl:8080)
  • inny protokół (np. strona http://przyklad.pl łączy się z https://przyklad.pl)

Jak działa CORS?

Cross-origin resource sharing to przede wszystkim zbiór nagłówków wymaganych do ustanowienia połączenia ze zdalną maszyną. W naszym przypadku z jednej strony będzie aplikacja webowa a z drugiej zdalne API. Istnieją dwa scenariusze działania CORS. Nasza przeglądarka internetowa sama wybierze jeden z nich sugerując się treścią jaką chcemy przesłać.

Proste zapytanie

Kiedy nasze zapytanie:

  • nie zawiera ciasteczka
  • Content-Type to application/x-www-form-urlencoded, multipart/form-data bądź też text-plain
  • korzysta z metody GET, HEAD lub POST
  • zawiera wyłącznie nagłówki z tej listy: Accept, Accept-Language, Content-Language, DPR, Downlink, Save-Data, Viewport-Width, Width

Do zapytania po stronie przeglądarki automatycznie doklejany jest nagłówek Origin z nazwą domeny, która wysyła to zapytanie. Nie możemy w żaden sposób zmienić tego nagłówka. Od serwera wymagane jest zwrócenie nagłówka Access-Control-Allow-Origin, który mówi naszej przeglądarce na połączenia z jakich domen zgadza się serwer. W przypadku gwiazdki „*” zgadzamy się na nawiązanie połączenia z każdym klientem. Odpowiedź z naszego API jest blokowana, kiedy:

Origin != Access-Control-Allow-Origin && Access-Control-Allow-Origin != *
Źródło: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

Zapytanie z Preflightem

Przy zapytaniach, które nie spełniają kryteriów podanych powyżej – ma zastosowanie scenariusz Preflight. Polega on na tym, że w pierwszej kolejności do naszego zewnętrznego API wysyłamy zapytanie typu OPTIONS, w którym mówimy naszemu docelowemu serwerowi jakiego typu połączenie chcemy nawiązać (jakiej użyjemy metody http, jakich nagłówków itd.). Jeśli weryfikacja zakończy się sukcesem, to wtedy zostanie wysłane docelowe zapytanie. Przeglądarka testuje serwer docelowy przesyłając dodatkowo nagłówki Access-Control-Request-Method oraz Access-Control-Request-Headers. Odpowiadają one kolejno za przechowywanie nazwy metody HTTP, której planujemy użyć w docelowym zapytaniu oraz za przechowywanie dodatkowych nagłówków HTTP. Jeśli serwer odpowie, że zgadza się na takie warunki połączenia, to wtedy zwraca kod 200.

Źródło: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

Ten poradnik ma na celu nauczyć Cię czegoś nowego, więc powtórzmy całą wiedzę na konkretnym przykładzie. Z jednej strony mamy do czynienia z aplikacją webową wyświetlaną przez przeglądarkę internetową, a z drugiej API znajdujące się na innym serwerze, które udostępnia nam jakieś zasoby.

Przeglądarka internetowa

Jeśli chodzi o nagłówki dodawane do zapytań HTTP przez przeglądarkę internetową – nie mamy możliwości ich edycji. Są ustawiane automatycznie w zależności od treści jakie chcemy przesłać oraz od domeny, z której wychodzi zapytanie. Są to następujące nagłówki:

  • Origin – przechowuje origin serwera, z którego wysyłane jest zapytanie
  • Access-Control-Request-Method – przechowuje nazwę metody HTTP, której planujemy użyć
  • Access-Control-Request-Headers – przechowuje dodatkowe nagłówki HTTP, które chcemy wysłać. np. Content-Type czy Accept.

W najprostszym przypadku, kiedy nasze zapytanie nie zawiera ciasteczka oraz Content-Type to application/x-www-form-urlencoded, multipart/form-data bądź też text-plain dodawany jest wyłącznie nagłówek Origin. W bardziej złożonych przypadkach mamy do czynienia z tak zwanym Preflight. Przed naszym zapytaniem docelowym wykonywane jest zapytanie typu OPTIONS, które zawiera dodatkowo nagłówki Access-Control-Request-Method oraz Access-Control-Request-Headers. Serwer docelowy musi bowiem wiedzieć czy zezwala na użycie wybranej metody HTTP oraz na przesłanie wybranych typów nagłówków. Na etapie Preflight ma miejsce inspekcja połączenia, które ma za chwilę nastąpić. Jeśli serwer stwierdzi, że nie wyraża zgody na tego typu połączenie, to nie dojdzie do wysłania docelowego zapytania przez przeglądarkę.

API

Inaczej sprawa ma się w przypadku naszego API. Możemy ustawić nagłówki CORS, które ma zwracać serwer. Są to następujące nagłówki:

  • Access-Control-Allow-Origin – originy, dla których zezwalamy na połączenie CORS. Na środowisku testowym możemy wstawić * aby zezwolić na wszelkie połączenia. Nie zalecamy tego rozwiązania w przypadku produkcji. Jeśli chcesz przesłać ciasteczko do autoryzacji użytkownika, to nie możesz skorzystać z * ! Musisz podać konkretny origin!
  • Access-Control-Allow-Methods – lista dozwolonych metod HTTP np. POST, GET, OPTIONS – TAK! To bardzo ważne, aby zezwolić na Preflight!
  • Access-Control-Allow-Headers
  • Access-Control-Max-Age
  • Access-Control-Allow-Credentials

Przedstawmy jeszcze raz wszystkie możliwe nagłówki CORS na diagramie.

Tak wygląda schemat połączenia pomiędzy przeglądarką internetową a API. W zależności od tego jakie zapytanie chcemy wysłać za pomocą przeglądarki – mamy do czynienia z Preflight bądź też nie.

Flowchart showing Simple and Preflight XHR.svg
Źródło: http://wikipedia.org

Podsumowanie

W czasach mikroserwisów bardzo często spotykamy się z sytuacją, w której front stoi na zupełnie innej maszynie bądź też na innym porcie niż API. Wiedza na temat CORS staje się więc podstawą. Mam nadzieję, że ten poradnik pomógł Ci zrozumieć z czym mamy do czynienia.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *