CORS: Não é possível usar curinga no Access-Control-Allow-Origin quando o sinalizador de credenciais for verdadeiro

296

Eu tenho uma configuração envolvendo

Servidor front-end (Node.js, domínio: localhost: 3000) <---> Back-end (Django, Ajax, domínio: localhost: 8000)

Navegador <- webapp <- Node.js (servir o aplicativo)

Navegador (webapp) -> Ajax -> Django (servir solicitações POST ajax)

Agora, meu problema aqui é com a configuração do CORS, que o webapp usa para fazer chamadas do Ajax para o servidor back-end. No chrome, eu continuo recebendo

Não é possível usar curinga no Access-Control-Allow-Origin quando o sinalizador de credenciais for verdadeiro.

também não funciona no Firefox.

Minha configuração do Node.js é:

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

E no Django eu estou usando esse middleware junto com isso

O webapp faz solicitações da seguinte forma:

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

Portanto, os cabeçalhos de solicitação que o aplicativo da web envia se parecem com:

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

E aqui está o cabeçalho da resposta:

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

Onde eu estou errando?!

Editar 1: eu estou usando chrome --disable-web-security, mas agora quero que as coisas realmente funcionem.

Edição 2: Resposta:

Então, solução para mim 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
fonte
1
Para mim é localhost: 3000 sem http, como este: CORS_ORIGIN_WHITELIST = ( 'localhost: 3000',)
Andrei
Você quer dizer que você desenvolve o frontend e o backend em um PC?
fanhualuojin154873
e quanto ao front-end e back-end em PC diferente?
fanhualuojin154873
@ixaxaar Por que você diz que com o http funciona para você? todos nós apenas '' localhost: 3000 '' funciona.
244boy
@ 244boy sim, o ponto não é o http, é /o final. Suponho que omitir o http possa funcionar, mas eu não trabalho nisso há alguns anos, então não sei o que funciona agora!
Ixaxaar 17/0318

Respostas:

247

Isso faz parte da segurança, você não pode fazer isso. Se você deseja permitir credenciais, Access-Control-Allow-Originnão deve usar *. Você precisará especificar o protocolo exato + domínio + porta. Para referência, consulte estas perguntas:

  1. Subdomínios, portas e protocolos curinga de acesso-controle-permissão-origem
  2. Compartilhamento de recursos entre origens com credenciais

Além disso, *é muito permissivo e impediria o uso de credenciais. Então, defina http://localhost:3000ou http://localhost:8000como o cabeçalho de origem de permissão.

user568109
fonte
45
Mas e se houver mais de um domínio?
Aroth # 8/14
13
@aroth Você pode dar uma lista de domínios. Pergunta relacionada: stackoverflow.com/questions/1653308/…
user568109 8/08
13
@ user568109 Você poderia explicar "Além disso *é muito permissivo e impediria o uso de credenciais".
Hugo Wood
12
Qual é o "domínio exato" se a solicitação vier do dispositivo móvel, como pode acontecer com o Cordova?
Christian
8
@ Christian meio velho, mas se alguém ainda estiver curioso, esse problema ocorre apenas para aplicativos em execução nos navegadores, porque esse erro é gerado pelo navegador por razões de segurança. Outros clientes, como um aplicativo móvel, carteiro ou qualquer outro código de back-end que use o cliente http para fazer uma solicitação, não terão esse problema; portanto, você não precisa se preocupar com a origem e o domínio exato .
Alisson
32

Se você estiver usando o middleware CORS e quiser enviar um withCredentialboolean true, poderá configurar o CORS assim:

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

Se você estiver usando, expresspoderá usar o pacote cors para permitir o CORS assim, em vez de escrever seu middleware;

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

app.use(cors());

app.get(function(req,res){ 
  res.send('hello');
});
Bulkan
fonte
12
Ah, agora que é mais conveniente, no entanto, o resultado é o mesmo :( BTW, eu estou usandoapp.use(cors({credentials: true}));
ixaxaar
1
Você pode querer examinar esse middleware do Django CORS que é testado.
Bulkan
1
Então você tem dois middlewares do Django? Eu usaria apenas o django-cors-headeraplicativo. Certifique-se de adicionar localhost à CORS_ORIGIN_WHITELISTconfiguração e CORS_ALLOW_CREDENTIALSaoTrue
Bulkan
1
Sim cara, tentou isso antes sem sucesso, tinha CORS_ORIGIN_ALLOW_ALL = True, CORS_ORIGIN_WHITELIST = ( 'localhost' )e CORS_ALLOW_CREDENTIALS = True eu recebo esses cabeçalhos: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
Depois de ler esta documentação: github.com/expressjs/corsuse i usando esta config: app.use (cors ({credenciais: true, origem: ' localhost: 3001 '})); está trabalhando para mim.
alelo
11

tente:

const cors = require('cors')

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

}
app.use(cors(corsOptions));
Escudo de ferro
fonte
6

Se você deseja permitir todas as origens e manter as credenciais verdadeiras, isso funcionou para mim:

app.use(cors({
  origin: function(origin, callback){
    return callback(null, true);
  },
  optionsSuccessStatus: 200,
  credentials: true
}));
Squirrl
fonte
@TSlegaitis Haha, é por isso que funciona para todas as origens, mas mantém as credenciais. Eu não recomendaria por segurança, mas funciona.
Squirrl 15/02
2

(Editar) O complemento recomendado anteriormente não está mais disponível, você pode tentar outro


Para fins de desenvolvimento no Chrome, a instalação desse complemento eliminará esse erro 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.

Após a instalação, adicione seu padrão de URL ao Intercepted URLsclicando no ícone do AddOn ( CORS , verde ou vermelho) e preenchendo a caixa de texto apropriada. Um exemplo de padrão de URL para adicionar aqui que funcionará http://localhost:8080seria:*://*

eriel marimon
fonte
Eu entendi logo após a instalação, alguma idéia?
Jalil
Funcionou para mim. Aviso Se você tiver outros complementos semelhantes, precisará desinstalá-lo antes de tentar este.
FilippoG 13/09/19
por favor corrija o link quebrado
Luk Aron
Parece que o complemento original foi removido, eu adicionei uma nova recomendação como (Editar) na parte superior
eriel marimon
1

Isso funciona para mim no desenvolvimento, mas não posso aconselhar que, na produção, é apenas uma maneira diferente de concluir o trabalho que ainda não foi mencionado, mas provavelmente não é o melhor. Enfim, aqui vai:

Você pode obter a origem da solicitação e usá-la no cabeçalho da resposta. Veja como fica expresso:

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

Não sei como seria a configuração do python, mas isso deve ser fácil de traduzir.

Renaud
fonte
O Mozilla Dev Docs expande a idéia de alterar a origem permitida para a origem da solicitação. É recomendável adicionar um cabeçalho de resposta HTTP 'Vary: Origin' e domínios permitidos na lista de permissões.
Ramzis 10/06