CORS: Nie można użyć symboli wieloznacznych w Access-Control-Allow-Origin, gdy flaga poświadczeń jest prawdziwa

295

Mam konfigurację obejmującą

Serwer frontendowy (Node.js, domena: localhost: 3000) <---> Backend (Django, Ajax, domena: localhost: 8000)

Przeglądarka <- webapp <- Node.js (Serve the app)

Przeglądarka (webapp) -> Ajax -> Django (Służy do ajax POST żądania)

Teraz mój problem dotyczy konfiguracji CORS, której używa aplikacja internetowa do wykonywania połączeń Ajax z serwerem zaplecza. W chrome wciąż się dostaję

Nie można używać symboli wieloznacznych w Access-Control-Allow-Origin, gdy flaga poświadczeń jest prawdziwa.

nie działa również na Firefoxie.

Moja konfiguracja Node.js to:

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', 'http://localhost:8000/');
    res.header('Access-Control-Allow-Credentials', true);
    res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE');
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
};

W Django używam tego oprogramowania pośredniego wraz z tym

Aplikacja internetowa jako taka wysyła żądania:

$.ajax({
    type: "POST",
    url: 'http://localhost:8000/blah',
    data: {},
    xhrFields: {
        withCredentials: true
    },
    crossDomain: true,
    dataType: 'json',
    success: successHandler
});

Nagłówki żądania wysyłane przez aplikację internetową wyglądają więc tak:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: "Origin, X-Requested-With, Content-Type, Accept"
Access-Control-Allow-Methods: 'GET,PUT,POST,DELETE'
Content-Type: application/json 
Accept: */*
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Cookie: csrftoken=***; sessionid="***"

A oto nagłówek odpowiedzi:

Access-Control-Allow-Headers: Content-Type,*
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE
Content-Type: application/json

Gdzie się mylę ?!

Edycja 1: Używam chrome --disable-web-security, ale teraz chcę, aby rzeczy faktycznie działały.

Edycja 2: Odpowiedź:

Tak więc rozwiązanie dla mnie django-cors-headersconfig:

CORS_ORIGIN_ALLOW_ALL = False
CORS_ALLOW_CREDENTIALS = True
CORS_ORIGIN_WHITELIST = (
    'http://localhost:3000' # Here was the problem indeed and it has to be http://localhost:3000, not http://localhost:3000/
)
ixaxaar
źródło
1
Dla mnie jest to localhost: 3000 bez http, jak to: CORS_ORIGIN_WHITELIST = ('localhost: 3000',)
Andrei
Czy masz na myśli, że używasz programowania frontendu i backendu na jednym komputerze?
fanhualuojin154873,
co powiesz na frontend i backend na innym komputerze?
fanhualuojin154873,
@ixaxaar, dlaczego mówisz, że http działa dla Ciebie? wszyscy działamy tylko jako „localhost: 3000”.
244boy
@ 244boy tak, nie chodzi o httpto, że jest /na końcu. Przypuszczam, że pominięcie http może działać, ale tak naprawdę nie pracowałem nad tym przez kilka lat, więc nie wiem, co teraz działa!
ixaxaar,

Odpowiedzi:

247

Jest to część bezpieczeństwa, nie możesz tego zrobić. Jeśli chcesz zezwolić na poświadczenia, Access-Control-Allow-Originnie możesz ich używać *. Musisz podać dokładny protokół + domena + port. W celach informacyjnych zobacz następujące pytania:

  1. Subdomeny, porty i protokoły Access-Control-Allow-Origin
  2. Udostępnianie zasobów między źródłami za pomocą poświadczeń

Poza tym *jest zbyt liberalny i nie pozwoliłby na użycie poświadczeń. Więc ustaw http://localhost:3000lub http://localhost:8000jako nagłówek zezwolenia na początek.

użytkownik568109
źródło
45
Ale co, jeśli istnieje więcej niż jedna domena?
aroth
13
@aroth Możesz podać listę domen. Powiązane pytanie: stackoverflow.com/questions/1653308/…
user568109
13
@ user568109 Czy możesz wyjaśnić „Poza tym *jest zbyt pobłażliwe i uniemożliwiłoby użycie poświadczeń”.
Hugo Wood,
12
Jaka jest „dokładna domena”, jeśli żądanie pochodzi z urządzenia mobilnego, tak jak może się zdarzyć w przypadku Cordova?
Christian
8
@Christian trochę stary, ale jeśli ktoś nadal jest ciekawy, ten problem występuje tylko w aplikacjach działających w przeglądarkach, ponieważ ten błąd jest zgłaszany przez przeglądarkę ze względów bezpieczeństwa. Inni klienci, np. Aplikacja mobilna, listonosz lub inny kod zaplecza używający klienta HTTP do złożenia żądania, nie będą mieli tego problemu, więc nie musisz się martwić o pochodzenie i dokładną domenę .
Alisson
32

Jeśli używasz oprogramowania pośredniego CORS i chcesz wysłać wartość withCredentiallogiczną true, możesz skonfigurować CORS w następujący sposób:

var cors = require('cors');    
app.use(cors({credentials: true, origin: 'http://localhost:3000'}));
Hamid
źródło
16

Jeśli używasz express, możesz użyć pakietu cors , aby zezwolić na CORS, zamiast pisać oprogramowanie pośrednie;

var express = require('express')
, cors = require('cors')
, app = express();

app.use(cors());

app.get(function(req,res){ 
  res.send('hello');
});
Bulkan
źródło
12
Ach, teraz jest to wygodniejsze, jednak wynik jest taki sam :( BTW, używamapp.use(cors({credentials: true}));
ixaxaar
1
Można zajrzeć do tego Django Cors middleware, która jest testowana.
Bulkan
1
Masz więc dwa oprogramowanie pośrednie Django? Używałbym tylko django-cors-headeraplikacji. Pamiętaj, aby dodać localhost do CORS_ORIGIN_WHITELISTustawienia i ustawić CORS_ALLOW_CREDENTIALSnaTrue
Bulkan
1
Tak człowiek, który próbował wcześniej bezskutecznie, miał CORS_ORIGIN_ALLOW_ALL = True, CORS_ORIGIN_WHITELIST = ( 'localhost' )i CORS_ALLOW_CREDENTIALS = True mam te nagłówki:Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: http://localhost:3000/ Access-Control-Allow-Methods: POST,GET,OPTIONS,PUT,DELETE Content-Type: application/json
ixaxaar
5
Po przeczytaniu tej dokumentacji: github.com/expressjs/corsuse i korzystam z tej konfiguracji: app.use (cors ({credentials: true, origin: ' localhost: 3001 '})); pracuje dla mnie.
allel
11

Spróbuj:

const cors = require('cors')

const corsOptions = {
    origin: 'http://localhost:4200',
    credentials: true,

}
app.use(cors(corsOptions));
Żelazna tarcza
źródło
6

Jeśli chcesz zezwolić na wszystkie źródła i zachować poświadczenia prawdziwe, działało to dla mnie:

app.use(cors({
  origin: function(origin, callback){
    return callback(null, true);
  },
  optionsSuccessStatus: 200,
  credentials: true
}));
Squirrl
źródło
@TSlegaitis Haha tak, dlatego działa dla wszystkich źródeł, ale zachowuje poświadczenia. Nie poleciłbym tego ze względów bezpieczeństwa, ale działa.
Squirrl
2

(Edytuj) Zalecany wcześniej dodatek nie jest już dostępny, możesz wypróbować ten inny


Do celów programistycznych w Chrome zainstalowanie tego dodatku pozbywa się tego konkretnego błędu:

Access to XMLHttpRequest at 'http://192.168.1.42:8080/sockjs-node/info?t=1546163388687' 
from origin 'http://localhost:8080' has been blocked by CORS policy: The value of the 
'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' 
when the request's credentials mode is 'include'. The credentials mode of requests 
initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

Po zainstalowaniu upewnij się, że dodajesz wzór adresu URL, Intercepted URLsklikając ikonę AddOn ( CORS , zielony lub czerwony) i wypełniając odpowiednie pole tekstowe. Przykładowy wzorzec adresu URL do dodania tutaj, który będzie działał http://localhost:8080, to:*://*

Eriel Marimon
źródło
Mam go zaraz po instalacji, jakieś pomysły?
Jalil
To zadziałało dla mnie. Ostrzeżenie, jeśli masz inne podobne dodatki, musisz je odinstalować przed wypróbowaniem tego.
FilippoG
napraw zepsuty link
Luk Aron
Wygląda na to, że oryginalny dodatek został usunięty, dodałem nową rekomendację jako (Edytuj) u góry
eriel marimon
1

Działa to dla mnie na etapie rozwoju, ale nie mogę powiedzieć, że w produkcji jest to tylko inny sposób wykonania pracy, o którym jeszcze nie wspomniano, ale prawdopodobnie nie jest najlepszy. W każdym razie tutaj idzie:

Możesz uzyskać pochodzenie z żądania, a następnie użyć go w nagłówku odpowiedzi. Oto jak to wygląda ekspresowo:

app.use(function(req, res, next) {
  res.header('Access-Control-Allow-Origin', req.header('origin') );
  next();
});

Nie wiem, jak by to wyglądało w konfiguracji Pythona, ale powinno to być łatwe do przetłumaczenia.

Renaud
źródło
Dokumenty deweloperów Mozilli rozwijają pomysł zmiany dozwolonego źródła na ten z żądania. Zaleca się dodanie nagłówka odpowiedzi HTTP „Vary: Origin” i dozwolonych domen na białej liście.
Ramzis