Współdzielenie zasobów pomiędzy serwerami z różnych domen (CORS)

Bezpieczne udostępnianie zasobów z różnych domen

Mariko Kosaka

Zasada takiego samego pochodzenia w przeglądarce blokuje odczytywanie zasobów z innej domeny. Ten mechanizm uniemożliwia złośliwym witrynom odczytywanie danych z innych witryn, ale też utrudnia korzystanie z nich w uzasadnionych przypadkach.

Nowoczesne aplikacje internetowe często chcą uzyskiwać zasoby z innej domeny, np. pobierać dane JSON z innej domeny lub wczytywać obrazy z innej witryny do elementu <canvas>. Mogą to być zasoby publiczne, które powinny być dostępne dla każdego, ale zasada takiego samego pochodzenia blokuje ich użycie. Deweloperzy historycznie stosowali obejścia, takie jak JSONP.

Współdzielenie zasobów pomiędzy serwerami z różnych domen (CORS) rozwiązuje ten problem w standardowy sposób. Włączenie CORS pozwala serwerowi poinformować przeglądarkę, że może ona używać dodatkowej domeny.

Jak działa żądanie zasobu w internecie?

żądanie i odpowiedź,
Ilustracja żądania klienta i odpowiedzi serwera.

Przeglądarka i serwer mogą wymieniać dane przez sieć za pomocą protokołu przesyłania hipertekstu (HTTP). HTTP określa reguły komunikacji między osobą wysyłającą żądanie a osobą odpowiadającą, w tym informacje potrzebne do uzyskania zasobu.

Nagłówek HTTP negocjuje wymianę wiadomości między klientem a serwerem i służy do określania dostępu. Zarówno żądanie przeglądarki, jak i odpowiedź serwera są podzielone na nagłówek i treść.

Informacje o wiadomości, takie jak jej typ lub kodowanie. Nagłówek może zawierać r óżne informacje wyrażone jako pary klucz-wartość. Nagłówek żądania i nagłówek odpowiedzi zawierają różne informacje.

Przykładowy nagłówek żądania

Accept: text/html
Cookie: Version=1

Ten nagłówek jest odpowiednikiem stwierdzenia „Chcę otrzymać w odpowiedzi kod HTML. Oto mój plik cookie”.

Przykładowy nagłówek odpowiedzi

Content-Encoding: gzip
Cache-Control: no-store

Ten nagłówek jest odpowiednikiem stwierdzenia „Dane w tej odpowiedzi są zakodowane za pomocą gzip. Nie zapisuj ich w pamięci podręcznej”.

Treść

Sama wiadomość. Może to być zwykły tekst, plik binarny obrazu, JSON, HTML lub wiele innych formatów.

Jak działa CORS?

Zasada takiego samego pochodzenia nakazuje przeglądarce blokować żądania dotyczące zasobów z innej domeny. Gdy potrzebujesz zasobu publicznego z innej domeny, serwer udostępniający ten zasób informuje przeglądarkę, że domena wysyłająca żądanie może uzyskać dostęp do tego zasobu. Przeglądarka zapamiętuje to i zezwala na współdzielenie zasobów pomiędzy serwerami z różnych domen w przypadku tego zasobu.

Krok 1. Żądanie klienta (przeglądarki)

Gdy przeglądarka wysyła żądanie dotyczące zasobów z innej domeny, dodaje nagłówek Origin z bieżącą domeną (schematem, hostem i portem).

Krok 2. Odpowiedź serwera

Gdy serwer zobaczy ten nagłówek i będzie chciał zezwolić na dostęp, doda do odpowiedzi nagłówek Access-Control-Allow-Origin określający domenę wysyłającą żądanie (lub *, aby zezwolić na dostęp z dowolnej domeny).

Krok 3. Przeglądarka otrzymuje odpowiedź

Gdy przeglądarka zobaczy tę odpowiedź z odpowiednim nagłówkiem Access-Control-Allow-Origin, udostępni dane odpowiedzi witrynie klienta.

Udostępnianie danych logowania za pomocą CORS

Ze względu na ochronę prywatności CORS jest zwykle używany w przypadku żądań anonimowych, w których osoba wysyłająca żądanie nie jest identyfikowana. Jeśli chcesz wysyłać pliki cookie podczas korzystania z CORS, które mogą identyfikować nadawcę, musisz dodać dodatkowe nagłówki do żądania i odpowiedzi.

Żądanie

Dodaj credentials: 'include' do opcji pobierania, jak w tym przykładzie. Obejmuje to plik cookie z żądaniem w ten sposób:

fetch('https://example.com', {
  mode: 'cors',
  credentials: 'include'
})

Odpowiedź

Wartość Access-Control-Allow-Origin musi być ustawiona na konkretną domenę (bez symbolu wieloznacznego *), a wartość Access-Control-Allow-Credentials musi być ustawiona na true.

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true

Żądania wstępne dotyczące złożonych wywołań HTTP

Gdy aplikacja internetowa wysyła złożone żądanie HTTP, przeglądarka dodaje na początku łańcucha żądań żądanie wstępne.

Specyfikacja CORS definiuje złożone żądanie w ten sposób:

  • Żądanie, które używa metod innych niż GET, POST lub HEAD.
  • Żądanie, które zawiera nagłówki inne niż Accept, Accept-Language lub Content-Language.
  • Żądanie, które ma nagłówek Content-Type inny niż application/x-www-form-urlencoded, multipart/form-data lub text/plain.

Przeglądarki automatycznie tworzą wszystkie niezbędne żądania wstępne i wysyłają je przed właściwą wiadomością żądania. Żądanie wstępne to żądanie OPTIONS, jak w tym przykładzie:

OPTIONS /data HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: DELETE

Po stronie serwera aplikacja odbierająca żądanie odpowiada na żądanie wstępne, podając informacje o metodach, które aplikacja akceptuje z tej domeny:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, DELETE, HEAD, OPTIONS

Odpowiedź serwera może też zawierać nagłówek Access-Control-Max-Age, który określa czas w sekundach, przez jaki mają być przechowywane w pamięci podręcznej wyniki procesu wstępnego. Dzięki temu klient może wysyłać wiele złożonych żądań bez konieczności powtarzania procesu wstępnego.