CORS: no se puede usar comodín en Access-Control-Allow-Origin cuando el indicador de credenciales es verdadero

296

Tengo una configuración que involucra

Servidor frontend (Node.js, dominio: localhost: 3000) <---> Backend (Django, Ajax, dominio: localhost: 8000)

Navegador <- webapp <- Node.js (Servir la aplicación)

Navegador (aplicación web) -> Ajax -> Django (Servir solicitudes POST de ajax)

Ahora, mi problema aquí es con la configuración de CORS que utiliza la aplicación web para hacer llamadas Ajax al servidor de fondo. En cromo, sigo obteniendo

No se puede usar comodín en Access-Control-Allow-Origin cuando el indicador de credenciales es verdadero.

tampoco funciona en firefox.

Mi configuración de Node.js es:

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

Y en Django estoy usando este middleware junto con este

La aplicación web realiza solicitudes como tales:

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

Entonces, los encabezados de solicitud que envía la aplicación web se ven así:

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

Y aquí está el encabezado de respuesta:

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

¿Dónde me estoy equivocando?

Edición 1: He estado usando chrome --disable-web-security, pero ahora quiero que las cosas realmente funcionen.

Edición 2: Respuesta:

Entonces, la solución para mí 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
fuente
1
Para mí es localhost: 3000 sin http, así: CORS_ORIGIN_WHITELIST = ('localhost: 3000',)
Andrei
¿Quieres decir que usas desarrollar el frontend y el backend en una PC?
fanhualuojin154873
¿Qué tal el frontend y el backend en diferentes PC?
fanhualuojin154873
@ixaxaar ¿por qué dices que con el http te funciona? Todos solo `` localhost: 3000 '' funciona.
244boy
@ 244boy, sí, el punto no es el http, es /el final. Supongo que omitir http podría funcionar, pero realmente no he trabajado en estas cosas durante algunos años, ¡así que realmente no sé qué funciona ahora!
ixaxaar

Respuestas:

247

Esto es parte de la seguridad, no puedes hacer eso. Si desea permitir credenciales, entonces Access-Control-Allow-Originno debe usarlas *. Deberá especificar el protocolo exacto + dominio + puerto. Para referencia vea estas preguntas:

  1. Subdominios, puertos y protocolos de comodines Access-Control-Allow-Origin
  2. Intercambio de recursos de origen cruzado con credenciales

Además *es demasiado permisivo y derrotaría el uso de credenciales. Establezca http://localhost:3000o http://localhost:8000como el encabezado de origen permitido.

usuario568109
fuente
45
Pero, ¿y si hay más de un dominio?
Aroth
13
@aroth Puedes dar una lista de dominios. Pregunta relacionada: stackoverflow.com/questions/1653308/…
user568109
13
@ user568109 ¿Podría explicar "Además *es demasiado permisivo y vencería el uso de credenciales"?
Hugo Wood
12
¿Cuál es el "dominio exacto" si la solicitud proviene de un dispositivo móvil, como puede suceder con Cordova?
Christian
8
@Christian es un poco viejo, pero si alguien todavía tiene curiosidad, este problema ocurre solo para las aplicaciones que se ejecutan en los navegadores, porque este error es arrojado por el navegador por razones de seguridad. Otros clientes, como una aplicación móvil, cartero o cualquier otro código de back-end que use el cliente http para realizar una solicitud, no tendrán este problema, por lo que no tiene que preocuparse por el origen y el dominio exacto .
Alisson
32

Si está utilizando el middleware CORS y desea enviar withCredentialboolean true, puede configurar CORS de esta manera:

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

Si estas usando express , puede usar el paquete cors para permitir CORS así en lugar de escribir su middleware;

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

app.use(cors());

app.get(function(req,res){ 
  res.send('hello');
});
Bulkan
fuente
12
Ah, ahora eso es más conveniente, sin embargo, el resultado es el mismo :( Por cierto, estoy usandoapp.use(cors({credentials: true}));
ixaxaar
1
Es posible que desee ver este middleware Django CORS que se prueba.
Bulkan
1
¿Entonces tienes dos middlewares Django? Solo usaría la django-cors-headeraplicación. Asegúrese de agregar localhost a la CORS_ORIGIN_WHITELISTconfiguración y establecer CORS_ALLOW_CREDENTIALSenTrue
Bulkan
1
Sí hombre, lo intenté antes en vano, lo hice CORS_ORIGIN_ALLOW_ALL = True, CORS_ORIGIN_WHITELIST = ( 'localhost' )y CORS_ALLOW_CREDENTIALS = Trueobtengo estos encabezados: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
55
Después de leer esta documentación: github.com/expressjs/corsuse estoy usando esta configuración: app.use (cors ({credentials: true, origin: ' localhost: 3001 '})); esta trabajando para mi
allel
11

intentalo:

const cors = require('cors')

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

}
app.use(cors(corsOptions));
Escudo de hierro
fuente
6

Si desea permitir todos los orígenes y mantener verdaderas las credenciales, esto funcionó para mí:

app.use(cors({
  origin: function(origin, callback){
    return callback(null, true);
  },
  optionsSuccessStatus: 200,
  credentials: true
}));
Squirrl
fuente
@TSlegaitis Jaja sí, es por eso que funciona para todos los orígenes, pero mantiene credenciales. No lo recomendaría por seguridad, pero funciona.
Squirrl
2

(Editar) El complemento previamente recomendado ya no está disponible, puedes probar este otro


Para fines de desarrollo en Chrome, la instalación de este complemento eliminará ese error específico:

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.

Después de la instalación, asegúrese de agregar su patrón de URL al Intercepted URLshacer clic en el ícono de Complemento ( CORS , verde o rojo) y completar el cuadro de texto correspondiente. Un patrón de URL de ejemplo para agregar aquí que funcionará http://localhost:8080sería:*://*

eriel marimon
fuente
Lo obtuve justo después de instalarlo, ¿alguna idea?
Jalil
Funcionó para mi. Advertencia: si tiene otros complementos similares, debe desinstalarlo antes de probar este.
FilippoG
por favor arregle el enlace roto
Luk Aron
Parece que se eliminó el complemento original, agregué una nueva recomendación como (Editar) en la parte superior
eriel marimon
1

Esto funciona para mí en el desarrollo, pero no puedo aconsejar que en la producción, es solo una forma diferente de hacer el trabajo que aún no se ha mencionado pero que probablemente no sea la mejor. De todos modos aquí va:

Puede obtener el origen de la solicitud, luego usarlo en el encabezado de la respuesta. Así es como se ve en express:

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

No sé cómo se vería eso con su configuración de Python, pero eso debería ser fácil de traducir.

Renaud
fuente
Mozilla Dev Docs amplía la idea de cambiar el origen permitido al de la solicitud. Se sugiere agregar un encabezado de respuesta HTTP 'Variar: origen' y una lista blanca de dominios permitidos.
Ramzis