CORS: In Access-Control-Allow-Origin kann kein Platzhalter verwendet werden, wenn das Flag für Anmeldeinformationen wahr ist

296

Ich habe ein Setup mit

Frontend-Server (Node.js, Domäne: localhost: 3000) <---> Backend (Django, Ajax, Domäne: localhost: 8000)

Browser <- webapp <- Node.js (App bereitstellen)

Browser (Webapp) -> Ajax -> Django (Ajax-POST-Anfragen bedienen)

Mein Problem hier ist das CORS-Setup, mit dem die Webanwendung Ajax-Aufrufe an den Back-End-Server ausführt. In Chrom bekomme ich immer

In Access-Control-Allow-Origin kann kein Platzhalter verwendet werden, wenn das Flag für Anmeldeinformationen wahr ist.

funktioniert auch nicht mit Firefox.

Mein Node.js-Setup lautet:

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();
};

Und in Django verwende ich diese Middleware zusammen mit dieser

Die Webanwendung stellt Anfragen als solche:

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

Die von der Webanwendung gesendeten Anforderungsheader sehen also folgendermaßen aus:

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="***"

Und hier ist der Antwortheader:

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

Wo gehe ich falsch?!

Edit 1: Ich habe verwendet chrome --disable-web-security, möchte aber jetzt, dass die Dinge tatsächlich funktionieren.

Edit 2: Antwort:

Also, Lösung für mich 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
quelle
1
Für mich ist es localhost: 3000 ohne http, wie folgt: CORS_ORIGIN_WHITELIST = ('localhost: 3000',)
Andrei
Meinen Sie damit, dass Sie das Frontend und das Backend in einem PC entwickeln?
fanhualuojin154873
Wie wäre es mit dem Frontend und Backend in verschiedenen PCs?
fanhualuojin154873
@ixaxaar warum sagst du mit dem http funktioniert für dich? wir alle arbeiten nur "localhost: 3000".
244boy
@ 244boy ja der Punkt ist nicht der http, es ist der /am Ende. Ich nehme an, das Weglassen von http könnte funktionieren, aber ich habe einige Jahre nicht wirklich an diesem Zeug gearbeitet, also weiß ich nicht wirklich, was jetzt funktioniert!
Ixaxaar

Antworten:

247

Dies ist ein Teil der Sicherheit, das können Sie nicht. Wenn Sie Anmeldeinformationen zulassen möchten, Access-Control-Allow-Origindürfen Sie diese nicht verwenden *. Sie müssen das genaue Protokoll + Domäne + Port angeben. Als Referenz siehe diese Fragen:

  1. Platzhalter-Subdomains, -Ports und -Protokolle für Zugriffskontrolle-Zulassen-Ursprung
  2. Ursprungsübergreifende Ressourcenfreigabe mit Anmeldeinformationen

Außerdem *ist es zu freizügig und würde die Verwendung von Anmeldeinformationen verhindern. Stellen Sie also http://localhost:3000oder http://localhost:8000als zulässigen Ursprungsheader ein.

user568109
quelle
45
Aber was ist, wenn es mehr als eine Domain gibt?
aroth
13
@aroth Sie können eine Liste von Domains angeben. Verwandte Frage: stackoverflow.com/questions/1653308/…
user568109
13
@ user568109 Könnten Sie erklären, "Außerdem *ist zu freizügig und würde die Verwendung von Anmeldeinformationen verhindern."?
Hugo Wood
12
Was ist die "genaue Domain", wenn die Anfrage von einem mobilen Gerät kommt, wie es bei Cordova passieren kann?
Christian
8
@Christian ist ein bisschen alt, aber wenn jemand noch neugierig ist, tritt dieses Problem nur bei Anwendungen auf, die auf Browsern ausgeführt werden, da dieser Fehler aus Sicherheitsgründen vom Browser ausgelöst wird. Andere Clients wie eine mobile App, ein Postbote oder ein anderer Backend-Code, der einen http-Client verwendet, um eine Anfrage zu stellen, haben dieses Problem nicht, sodass Sie sich nicht um den Ursprung und die genaue Domain kümmern müssen .
Alisson
32

Wenn Sie CORS-Middleware verwenden und withCredentialboolean true senden möchten , können Sie CORS folgendermaßen konfigurieren:

var cors = require('cors');    
app.use(cors({credentials: true, origin: 'http://localhost:3000'}));
Hamid
quelle
16

Wenn Sie verwenden express, können Sie das cors- Paket verwenden, um CORS so zuzulassen, anstatt Ihre Middleware zu schreiben.

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

app.use(cors());

app.get(function(req,res){ 
  res.send('hello');
});
Bulkan
quelle
12
Ah, jetzt ist das bequemer, aber das Ergebnis ist das gleiche:app.use(cors({credentials: true}));
Übrigens
1
Vielleicht möchten Sie sich diese getestete Django CORS-Middleware ansehen .
Bulkan
1
Sie haben also zwei Django-Middlewares? Ich würde nur django-cors-headerApp verwenden. Stellen Sie sicher, dass Sie localhost zur CORS_ORIGIN_WHITELISTEinstellung hinzufügen und CORS_ALLOW_CREDENTIALSaufTrue
Bulkan
1
Yeah man, versucht , dass vor ohne Erfolg hatte CORS_ORIGIN_ALLOW_ALL = True, CORS_ORIGIN_WHITELIST = ( 'localhost' )und CORS_ALLOW_CREDENTIALS = True ich bekomme diese Header: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
Nach dem Lesen dieser Dokumentation: github.com/expressjs/corsuse Ich verwende diese Konfiguration: app.use (cors ({credentials: true, origin: ' localhost: 3001 '})); arbeitet für mich.
Allel
11

Versuch es:

const cors = require('cors')

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

}
app.use(cors(corsOptions));
Eisenschild
quelle
6

Wenn Sie alle Ursprünge zulassen und die Anmeldeinformationen wahr halten möchten, hat dies für mich funktioniert:

app.use(cors({
  origin: function(origin, callback){
    return callback(null, true);
  },
  optionsSuccessStatus: 200,
  credentials: true
}));
Eichhörnchen
quelle
@TSlegaitis Haha ja, deshalb funktioniert es für alle Ursprünge, behält aber die Anmeldeinformationen. Ich würde es aus Sicherheitsgründen nicht empfehlen, aber es funktioniert.
Eichhörnchen
2

(Bearbeiten) Das zuvor empfohlene Add-On ist nicht mehr verfügbar. Sie können es auch mit diesem anderen versuchen


Für Entwicklungszwecke in Chrome wird durch die Installation dieses Add-Ons dieser spezielle Fehler behoben:

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.

Intercepted URLsStellen Sie nach der Installation sicher, dass Sie Ihr URL-Muster zum hinzufügen, indem Sie auf das AddOn-Symbol ( CORS , grün oder rot) klicken und das entsprechende Textfeld ausfüllen. Ein Beispiel für ein URL-Muster, das hier hinzugefügt werden http://localhost:8080soll, ist:*://*

eriel marimon
quelle
Ich habe es gleich nach der Installation bekommen, irgendwelche Ideen?
Jalil
Es hat bei mir funktioniert. Warnung: Wenn Sie andere ähnliche Add-Ons haben, müssen Sie diese deinstallieren, bevor Sie dieses ausprobieren.
FilippoG
Bitte beheben Sie den defekten Link
Luk Aron
Scheint wie das Original add on entfernt wurde, habe ich eine neue Empfehlung als (Edit) an der Spitze
Eriel marimon
1

Dies funktioniert für mich in der Entwicklung, aber ich kann nicht raten, dass es in der Produktion nur eine andere Art ist, die Arbeit zu erledigen, die noch nicht erwähnt wurde, aber wahrscheinlich nicht die beste. Sowieso geht hier:

Sie können den Ursprung aus der Anforderung abrufen und diesen dann im Antwortheader verwenden. So sieht es im Express aus:

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

Ich weiß nicht, wie das mit Ihrem Python-Setup aussehen würde, aber das sollte leicht zu übersetzen sein.

Renaud
quelle
Mozilla Dev Docs erweitern die Idee, den zulässigen Ursprung in den aus der Anforderung zu ändern. Es wird empfohlen, einen HTTP-Antwortheader "Variieren: Ursprung" und Domänen mit zulässiger Whitelist hinzuzufügen.
Ramzis