XMLHttpRequest nie może załadować XXX Nie nagłówka „Access-Control-Allow-Origin”
tl; dr; O tej samej polityce pochodzenia
Mam proces Grunt, który inicjuje wystąpienie serwera express.js. Do tej pory działało to absolutnie dobrze, kiedy zaczęło wyświetlać pustą stronę, a w dzienniku błędów w konsoli programisty w Chrome (najnowsza wersja) pojawiały się następujące informacje:
XMLHttpRequest nie może załadować https://www.example.com/ Żądanego zasobu nie ma nagłówka „Access-Control-Allow-Origin”. Dlatego źródło „ http: // localhost: 4300 ” nie ma dostępu.
Co powstrzymuje mnie przed dostępem do strony?
Odpowiedzi
tl; dr - Na końcu i nagłówkach odpowiedzi znajduje się podsumowanie, aby ułatwić znalezienie odpowiednich części. Zalecane jest jednak przeczytanie wszystkiego, ponieważ zapewnia przydatne tło do zrozumienia, dlaczego , dzięki temu łatwiej jest zobaczyć, jak można zastosować w różnych okolicznościach.
O tej samej polityce pochodzenia
To jest ta sama polityka pochodzenia . Jest to funkcja bezpieczeństwa wdrażana przez przeglądarki.
Twój konkretny przypadek pokazuje, jak jest zaimplementowany dla XMLHttpRequest (i uzyskasz identyczne wyniki, jeśli użyjesz funkcji pobierania), ale dotyczy to również innych rzeczy (takich jak obrazy załadowane do <canvas>
lub dokumenty załadowane do pliku <iframe>
), po prostu z nieco inne implementacje.
(Co dziwne, dotyczy to również czcionek CSS, ale to dlatego, że znalezione odlewnie nalegały na DRM, a nie kwestie bezpieczeństwa, które zwykle obejmuje ta sama polityka pochodzenia).
Standardowy scenariusz, który pokazuje potrzebę SOP, można przedstawić trzema znakami :
- Alicja to osoba z przeglądarką internetową
- Bob prowadzi witrynę internetową (
https://www.[website].com/
w Twoim przykładzie) - Mallory prowadzi stronę internetową (
http://localhost:4300
w twoim przykładzie)
Alicja jest zalogowana na stronie Boba i ma tam pewne poufne dane. Być może jest to firmowy intranet (dostępny tylko dla przeglądarek w sieci LAN) lub jej bankowość internetowa (dostępna tylko za pomocą pliku cookie, który otrzymujesz po wprowadzeniu nazwy użytkownika i hasła).
Alicja odwiedza witrynę Mallory, która ma JavaScript, który powoduje, że przeglądarka Alicji wysyła żądanie HTTP do witryny Boba (z jej adresu IP z plikami cookie itp.). Może to być tak proste, jak używanie XMLHttpRequest
i czytanie responseText
.
Polityka tego samego źródła przeglądarki zapobiega odczytaniu przez JavaScript danych zwróconych przez witrynę internetową Boba (do której Bob i Alicja nie chcą, aby Mallory miał do nich dostęp). (Należy pamiętać, że można na przykład wyświetlać obraz za pomocą <img>
elementu całej pochodzeniu, ponieważ zawartość obrazu nie jest narażona na JavaScript (lub Mallory) ... chyba że rzucisz płótno do mieszanki w takim przypadku będzie generują tego samego pochodzenia błąd naruszenia).
Dlaczego zasady dotyczące tego samego pochodzenia mają zastosowanie, jeśli uważasz, że nie powinny
Dla dowolnego adresu URL możliwe jest, że SOP nie jest potrzebny. Oto kilka typowych scenariuszy, w których ma to miejsce:
- Alice, Bob i Mallory to ta sama osoba.
- Bob podaje całkowicie publiczne informacje
… Ale przeglądarka nie ma możliwości dowiedzenia się, czy którekolwiek z powyższych jest prawdą, więc zaufanie nie jest automatyczne i stosowana jest SOP. Zezwolenie musi być wyraźnie udzielone, zanim przeglądarka przekaże dane, które otrzymała, do innej witryny.
Dlaczego ta sama polityka pochodzenia dotyczy tylko języka JavaScript na stronie internetowej
Rozszerzenia przeglądarki *
, karta Sieć w narzędziach programistycznych przeglądarki i aplikacje, takie jak Postman, są instalowane jako oprogramowanie. Nie przekazują danych z jednej witryny do kodu JavaScript należącego do innej witryny tylko dlatego, że odwiedziłeś tę inną witrynę . Instalacja oprogramowania zwykle wymaga bardziej świadomego wyboru.
Nie ma osoby trzeciej (Mallory), która jest uważana za ryzyko.
*
Rozszerzenia przeglądarki muszą być napisane ostrożnie, aby uniknąć problemów z różnymi źródłami. Zobacz na przykład dokumentację Chrome .
Dlaczego możesz wyświetlać dane na stronie bez czytania ich za pomocą JS
Istnieje szereg okoliczności, w których witryna Mallory może spowodować, że przeglądarka pobierze dane od strony trzeciej i wyświetli je (np. Poprzez dodanie <img>
elementu wyświetlającego obraz). Jednak JavaScript Mallory'ego nie może odczytać danych w tym zasobie, tylko przeglądarka Alicji i serwer Boba mogą to zrobić, więc jest to nadal bezpieczne.
CORS
Access-Control-Allow-Origin
HTTP odpowiedzi Nagłówek, o którym mowa w komunikacie o błędzie jest częścią CORS standardowych co pozwala Bob jawnie zezwolić na miejscu Mallory'ego aby uzyskać dostęp do danych za pośrednictwem przeglądarki Alicji.
Podstawowa implementacja obejmowałaby po prostu:
Access-Control-Allow-Origin: *
… W nagłówkach odpowiedzi, aby umożliwić dowolnej witrynie internetowej odczyt danych.
Access-Control-Allow-Origin: http://example.com/
… Pozwoliłoby na dostęp do niego tylko określonej witrynie, a Bob może dynamicznie wygenerować go na podstawie nagłówka Origin
żądania, aby umożliwić dostęp do niego wielu witrynom, ale nie wszystkim.
Specyfika sposobu, w jaki Bob ustawia ten nagłówek odpowiedzi, zależy od serwera HTTP Roberta i / lub języka programowania po stronie serwera. Istnieje zbiór przewodników dotyczących różnych typowych konfiguracji, które mogą być pomocne.
NB: Niektóre żądania są złożone i wysyłają żądanie OPCJI inspekcji wstępnej , na które serwer będzie musiał odpowiedzieć, zanim przeglądarka wyśle GET / POST / PUT / cokolwiek żąda JS. Implementacje CORS, które dodają tylko Access-Control-Allow-Origin
do określonych adresów URL, często są przez to omijane.
Oczywiście udzielenie pozwolenia przez CORS jest czymś, co Bob zrobiłby tylko wtedy, gdy:
- Dane nie były prywatne lub
- Mallory był zaufany
Ale ja nie jestem Bobem!
Mallory nie ma standardowego mechanizmu dodawania tego nagłówka, ponieważ musi on pochodzić ze strony internetowej Boba, nad którą ona nie kontroluje.
Jeśli Bob uruchamia publiczny interfejs API, może istnieć mechanizm włączający CORS (na przykład poprzez sformatowanie żądania w określony sposób lub opcję konfiguracji po zalogowaniu się do witryny portalu deweloperów dla witryny Roberta). Będzie to jednak musiał być mechanizm wdrożony przez Boba. Mallory mogła przeczytać dokumentację w witrynie Boba, aby sprawdzić, czy coś jest dostępne, lub porozmawiać z Bobem i poprosić go o wdrożenie CORS.
Komunikaty o błędach zawierające wzmiankę „Odpowiedź na inspekcję wstępną”
Niektóre żądania z różnych źródeł są wstępnie sprawdzane .
Dzieje się tak, gdy (z grubsza mówiąc) próbujesz wysłać żądanie między źródłami, które:
- Obejmuje dane uwierzytelniające, takie jak pliki cookie
- Nie można go wygenerować za pomocą zwykłego formularza HTML (np. Ma niestandardowe nagłówki lub typ zawartości, którego nie można użyć w formularzu
enctype
).
Jeśli robisz coś poprawnie, co wymaga inspekcji wstępnej
W takich przypadkach reszta tej odpowiedzi nadal ma zastosowanie, ale musisz również upewnić się, że serwer może nasłuchiwać żądania wstępnego (które będzie OPTIONS
(a nie GET
, POST
lub cokolwiek próbujesz wysłać) i odpowiedzieć na nie z odpowiednimi uprawnieniami Access-Control-Allow-Origin
nagłówek ale również Access-Control-Allow-Methods
i Access-Control-Allow-Headers
aby umożliwić specyficzne metody HTTP lub nagłówków.
Jeśli przez pomyłkę uruchamiasz inspekcję wstępną
Czasami ludzie popełniają błędy, próbując tworzyć żądania Ajax, a czasami powodują one potrzebę przeprowadzenia inspekcji wstępnej. Jeśli interfejs API jest przeznaczony do zezwalania na żądania między źródłami, ale nie wymaga niczego, co wymagałoby inspekcji wstępnej, może to spowodować przerwanie dostępu.
Typowe błędy, które to powodują, obejmują:
- próbuje umieścić
Access-Control-Allow-Origin
i inne nagłówki odpowiedzi CORS na żądanie. Te nie należą do żądania, nie robią nic pomocnego (jaki byłby sens systemu uprawnień, w którym mógłbyś przyznać sobie pozwolenie?) I muszą pojawić się tylko w odpowiedzi. - próba umieszczenia
Content-Type: application/json
nagłówka w żądaniu GET, które nie ma treści żądania, aby opisać zawartość (zwykle gdy autor myliContent-Type
iAccept
).
W każdym z tych przypadków usunięcie dodatkowego nagłówka żądania często wystarczy, aby uniknąć konieczności wykonywania inspekcji wstępnej (co rozwiąże problem podczas komunikacji z interfejsami API, które obsługują proste żądania, ale nie są wstępnie sprawdzane).
Nieprzezroczyste odpowiedzi
Czasami musisz wysłać żądanie HTTP, ale nie musisz czytać odpowiedzi. np. jeśli wysyłasz wiadomość dziennika na serwer w celu nagrania.
Jeśli korzystasz z fetch
interfejsu API (zamiast XMLHttpRequest
), można skonfigurować, aby nie spróbować użyć CORS.
Zwróć uwagę, że to nie pozwoli ci zrobić niczego, do czego potrzebujesz CORS. Nie będziesz w stanie odczytać odpowiedzi. Nie będzie można złożyć wniosku wymagającego inspekcji wstępnej.
Pozwoli ci to na proste żądanie, nie zobaczenie odpowiedzi i nie wypełni Developer Console komunikatami o błędach.
Jak to zrobić, wyjaśniono w komunikacie o błędzie Chrome wyświetlanym podczas wysyłania żądania przy użyciu fetch
i nie uzyskujesz pozwolenia na wyświetlenie odpowiedzi za pomocą CORS:
Dostęp do pobierania z „
https://example.com/
źródła pochodzenia”https://example.net
został zablokowany przez zasady CORS: BrakAccess-Control-Allow-Origin
nagłówka „ ” w żądanym zasobie. Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na „brak elementów”, aby pobrać zasób z wyłączonym mechanizmem CORS.
A zatem:
fetch("http://example.com", { mode: "no-cors" });
Alternatywy dla CORS
JSONP
Bob mógł również dostarczyć dane za pomocą hackowania, takiego jak JSONP, w ten sposób ludzie używali Ajax z różnych źródeł, zanim pojawił się CORS.
Działa poprzez prezentowanie danych w postaci programu JavaScript, który wstrzykuje dane na stronę Mallory'ego.
Wymaga, aby Mallory ufał Bobowi, że nie dostarczy złośliwego kodu.
Zwróć uwagę na wspólny motyw: witryna dostarczająca dane musi informować przeglądarkę, że strona trzecia może uzyskać dostęp do danych, które wysyła do przeglądarki.
Ponieważ JSONP działa poprzez dołączenie <script>
elementu w celu załadowania danych w postaci programu JavaScript, który wywołuje funkcję już na stronie, próba użycia techniki JSONP na adresie URL, który zwraca kod JSON, zakończy się niepowodzeniem - zwykle z błędem CORB - ponieważ JSON nie jest JavaScriptem.
Przenieś dwa zasoby do jednego źródła
Jeśli dokument HTML, w którym działa JS, a żądany adres URL ma to samo źródło (ma ten sam schemat, nazwę hosta i port), to te same zasady pochodzenia domyślnie przyznają uprawnienia. CORS nie jest potrzebny.
Pełnomocnik
Mallory mogłaby użyć kodu po stronie serwera do pobrania danych (które mogłaby następnie przekazać ze swojego serwera do przeglądarki Alicji przez HTTP jak zwykle).
Będzie to:
- dodaj nagłówki CORS
- przekonwertuj odpowiedź na JSONP
- istnieją w tym samym źródle co dokument HTML
Ten kod po stronie serwera może być napisany i obsługiwany przez stronę trzecią (taką jak CORS Anywhere). Zwróć uwagę na konsekwencje związane z prywatnością: strona trzecia może monitorować, kto jest pełnomocnikiem na swoich serwerach.
Bob nie musiałby udzielać żadnych uprawnień, aby to się stało.
Nie ma tu żadnych konsekwencji dla bezpieczeństwa, ponieważ jest to tylko między Mallory i Bobem. Bob nie może pomyśleć, że Mallory to Alice i przekazać Mallory dane, które powinny pozostać poufne między Alice i Bobem.
W związku z tym Mallory może używać tej techniki tylko do odczytywania danych publicznych .
Pamiętaj jednak, że pobieranie treści z cudzej witryny internetowej i wyświetlanie jej na własną rękę może stanowić naruszenie praw autorskich i stanowić podstawę do podjęcia kroków prawnych.
Pisanie czegoś innego niż aplikacja internetowa
Jak wspomniano w sekcji „Dlaczego zasada tego samego źródła ma zastosowanie tylko do języka JavaScript na stronie internetowej”, możesz uniknąć SOP, nie pisząc kodu JavaScript na stronie internetowej.
Nie oznacza to, że nie możesz dalej używać JavaScript i HTML, ale możesz je rozpowszechniać za pomocą innego mechanizmu, takiego jak Node-WebKit lub PhoneGap.
Rozszerzenia przeglądarki
Rozszerzenie przeglądarki może wstawić nagłówki CORS w odpowiedzi przed zastosowaniem tej samej zasady pochodzenia.
Mogą one być przydatne przy programowaniu, ale nie są praktyczne w przypadku witryny produkcyjnej (proszenie każdego użytkownika witryny o zainstalowanie rozszerzenia przeglądarki, które wyłącza funkcję zabezpieczeń przeglądarki, jest nierozsądne).
Zwykle działają również tylko z prostymi żądaniami (niepowodzenie podczas obsługi żądań OPCJI inspekcji wstępnej).
Posiadanie odpowiedniego środowiska programistycznego z lokalnym serwerem programistycznym jest zwykle lepszym podejściem.
Inne zagrożenia bezpieczeństwa
Należy zauważyć, że SOP / CORS nie łagodzą ataków XSS , CSRF lub SQL Injection, które muszą być obsługiwane niezależnie.
Podsumowanie
- Nie ma nic można zrobić w swoim kodu po stronie klienta, który pozwoli CORS dostęp do kogoś innego serwera.
- Jeśli kontrolujesz serwer, żądanie jest wysyłane do: Dodaj do niego uprawnienia CORS.
- Jeśli jesteś przyjazny osobie, która ją kontroluje: poproś ją o dodanie do niej uprawnień CORS.
- Jeśli jest to usługa publiczna:
- Przeczytaj ich dokumentację API, aby zobaczyć, co mówią o dostępie do niego za pomocą JavaScript po stronie klienta:
- Mogą zalecić użycie określonych adresów URL
- Mogą obsługiwać JSONP
- Mogą w ogóle nie obsługiwać dostępu między źródłami z kodu po stronie klienta (może to być celowa decyzja ze względów bezpieczeństwa, zwłaszcza jeśli musisz przekazać spersonalizowany klucz API w każdym żądaniu).
- Upewnij się, że nie uruchamiasz żądania inspekcji wstępnej, którego nie potrzebujesz. Interfejs API może przyznać uprawnienia do prostych żądań, ale nie dla żądań wstępnie sprawdzonych.
- Przeczytaj ich dokumentację API, aby zobaczyć, co mówią o dostępie do niego za pomocą JavaScript po stronie klienta:
- Jeśli żadne z powyższych nie ma zastosowania: poproś przeglądarkę, aby komunikowała się z Twoim serwerem, a następnie poproś serwer o pobranie danych z innego serwera i przekazanie ich dalej. (Istnieją również usługi hostowane przez inne firmy, które dołączają nagłówki CORS do publicznie dostępnych zasobów, z których można korzystać).
Serwer docelowy musi dopuszczać żądania między źródłami. Aby umożliwić przesyłanie ekspresowe, wystarczy obsłużyć żądanie opcji http:
app.options('/url...', function(req, res, next){
res.header('Access-Control-Allow-Origin', "*");
res.header('Access-Control-Allow-Methods', 'POST');
res.header("Access-Control-Allow-Headers", "accept, content-type");
res.header("Access-Control-Max-Age", "1728000");
return res.sendStatus(200);
});
Ponieważ nie jest to wymienione w zaakceptowanej odpowiedzi.
- Nie dotyczy to dokładnie tego pytania, ale może pomóc innym, którzy szukają tego problemu
- To jest coś, co możesz zrobić w swoim kodzie klienta, aby w niektórych przypadkach zapobiec błędom CORS .
Możesz skorzystać z prostych żądań .
Aby wykonać „Proste żądania”, wniosek musi spełniać kilka warunków. Np jedynie pozwalając POST
, GET
i HEAD
sposób, jak tylko pozwala na pewien podane nagłówki (można znaleźć wszystkie warunki tutaj ).
Jeśli kod klienta nie ustawia w żądaniu nagłówków, których dotyczy problem (np. „Akceptuj”), z poprawioną wartością, może się zdarzyć, że niektórzy klienci automatycznie ustawią te nagłówki na „niestandardowe” wartości, co spowoduje, że serwer nie zaakceptuje ich jako Proste żądanie - które spowoduje błąd CORS.
Dzieje się tak z powodu błędu CORS. CORS to skrót od Cross Origin Resource Sharing. W prostych słowach ten błąd występuje, gdy próbujemy uzyskać dostęp do domeny / zasobu z innej domeny.
Przeczytaj więcej na ten temat tutaj: Błąd CORS z jquery
Aby to naprawić, jeśli masz dostęp do innej domeny, będziesz musiał zezwolić na Access-Control-Allow-Origin na serwerze. Można to dodać w nagłówkach. Możesz to włączyć dla wszystkich żądań / domen lub określonej domeny.
Jak uzyskać działające żądanie wpisu dotyczące udostępniania zasobów między źródłami (CORS)
Te linki mogą pomóc
Ten problem z CORS nie był dalej rozwijany (z innych powodów).
Mam ten problem z innego powodu. Mój interfejs również zwraca błąd nagłówka „Access-Control-Allow-Origin”.
Po prostu wskazałem zły adres URL, aby ten nagłówek nie był poprawnie odzwierciedlony (w którym zakładałem, że tak). localhost (front end) -> wywołanie niezabezpieczonego http (przypuszczalnie https), upewnij się, że punkt końcowy interfejsu API z interfejsu wskazuje na właściwy protokół.
Mam ten sam błąd w konsoli Chrome.
Mój problem polegał na tym, że próbowałem przejść do witryny za pomocą http://
zamiast https://
. Nie było więc nic do naprawienia, wystarczyło przejść do tej samej witryny za pomocą https
.
Ten błąd kosztował mnie 2 dni. Sprawdziłem dziennik serwera, żądanie / odpowiedź opcji inspekcji wstępnej między przeglądarką Chrome / Edge a serwerem było w porządku. Głównym powodem jest to, że odpowiedź serwera GET / POST / PUT / DELETE dla XHTMLRequest musi mieć również następujący nagłówek:
access-control-allow-origin: origin
„Pochodzenie” znajduje się w nagłówku żądania (przeglądarka doda je do żądania za Ciebie). na przykład:
Origin: http://localhost:4221
możesz dodać nagłówek odpowiedzi, taki jak następujący, aby zaakceptować dla wszystkich:
access-control-allow-origin: *
lub nagłówek odpowiedzi dla konkretnego żądania, takiego jak:
access-control-allow-origin: http://localhost:4221
Komunikat w przeglądarkach jest niejasny do zrozumienia: „... Żądany zasób”
zauważ, że: CORS działa dobrze dla localhost. inny port oznacza inną domenę. jeśli pojawi się komunikat o błędzie, sprawdź konfigurację CORS po stronie serwera.