CORS: Tidak dapat menggunakan wildcard di Access-Control-Allow-Origin ketika flag kredensial benar

296

Saya memiliki pengaturan yang melibatkan

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

Browser <- webapp <- Node.js (Melayani aplikasi)

Browser (webapp) -> Ajax -> Django (Melayani permintaan POST ajax)

Sekarang, masalah saya di sini adalah dengan pengaturan CORS yang digunakan webapp untuk melakukan panggilan Ajax ke server backend. Di chrome, saya terus mendapatkan

Tidak dapat menggunakan wildcard di Access-Control-Allow-Origin ketika flag kredensial benar.

juga tidak berfungsi pada firefox.

Pengaturan Node.js saya adalah:

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

Dan di Django saya menggunakan middleware ini bersamaan dengan ini

Webapp membuat permintaan seperti itu:

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

Jadi, header permintaan yang dikirim webapp terlihat seperti:

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

Dan inilah tajuk respons:

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

Di mana saya salah ?!

Sunting 1: Saya telah menggunakan chrome --disable-web-security, tetapi sekarang ingin semuanya benar-benar berfungsi.

Sunting 2: Jawab:

Jadi, solusi untuk saya django-cors-headerskonfigurasi:

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
sumber
1
Bagi saya ini adalah localhost: 3000 tanpa http, seperti ini: CORS_ORIGIN_WHITELIST = ('localhost: 3000',)
Andrei
Apakah Anda bermaksud menggunakan frontend dan backend dalam satu PC?
fanhualuojin154873
bagaimana dengan frontend dan backend di PC yang berbeda?
fanhualuojin154873
@ixaxaar mengapa Anda mengatakan dengan http cocok untuk Anda? kita semua hanya `localhost: 3000'` berfungsi.
244boy
@ 244boy ya intinya bukan http, itu /pada akhirnya. Saya kira menghilangkan http bisa berhasil, tetapi saya tidak benar-benar mengerjakan hal ini selama beberapa tahun, jadi tidak benar-benar tahu apa yang berhasil sekarang!
ixaxaar

Jawaban:

247

Ini adalah bagian dari keamanan, Anda tidak dapat melakukan itu. Jika Anda ingin mengizinkan kredensial maka Anda Access-Control-Allow-Origintidak boleh menggunakannya *. Anda harus menentukan protokol + domain + port yang tepat. Untuk referensi, lihat pertanyaan-pertanyaan ini:

  1. Subdomain, port, dan protokol wildcard Access-Control-Allow-Origin
  2. Berbagi Sumberdaya Silang Asal dengan Kredensial

Selain *itu terlalu permisif dan akan mengalahkan penggunaan kredensial. Jadi atur http://localhost:3000atau http://localhost:8000sebagai header boleh asal.

pengguna568109
sumber
45
Tetapi bagaimana jika ada lebih dari satu domain?
Agustus
13
@aroth Anda dapat memberikan daftar domain. Pertanyaan terkait: stackoverflow.com/questions/1653308/…
user568109
13
@ user568109 Bisakah Anda menjelaskan "Selain *itu terlalu permisif dan akan mengalahkan penggunaan kredensial."?
Hugo Wood
12
Apa "domain persis" jika permintaan berasal dari perangkat seluler, seperti itu dapat terjadi dengan Cordova?
Christian
8
@Christian agak tua, tetapi jika ada yang masih penasaran, masalah ini hanya terjadi pada aplikasi yang berjalan di browser, karena kesalahan ini dilemparkan oleh browser untuk alasan keamanan. Klien lain seperti aplikasi seluler, tukang pos atau kode backend lainnya menggunakan klien http untuk membuat permintaan tidak akan memiliki masalah ini, jadi Anda tidak perlu khawatir tentang asal dan domain yang tepat .
Alisson
32

Jika Anda menggunakan CORS middleware dan Anda ingin mengirim withCredentialboolean true, Anda dapat mengkonfigurasi CORS seperti ini:

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

Jika Anda menggunakan, expressAnda dapat menggunakan paket kor untuk memungkinkan CORS seperti itu alih-alih menulis middleware Anda;

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

app.use(cors());

app.get(function(req,res){ 
  res.send('hello');
});
Bulkan
sumber
12
Ah, sekarang lebih nyaman, bagaimanapun, hasilnya sama :( BTW, saya menggunakanapp.use(cors({credentials: true}));
ixaxaar
1
Anda mungkin ingin melihat ke dalam ini middleware Django CORS yang diuji.
Bulkan
1
Jadi, Anda memiliki dua middlewares Django? Saya hanya akan menggunakan django-cors-headeraplikasi. Pastikan Anda menambahkan localhost ke CORS_ORIGIN_WHITELISTpengaturan dan set CORS_ALLOW_CREDENTIALSkeTrue
Bulkan
1
Ya man, mencoba itu sebelumnya tidak berhasil, telah CORS_ORIGIN_ALLOW_ALL = True, CORS_ORIGIN_WHITELIST = ( 'localhost' )dan CORS_ALLOW_CREDENTIALS = True saya mendapatkan header ini: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
Setelah membaca dokumentasi ini: github.com/expressjs/corsuse saya menggunakan config: app.use (cors ({credentials: true, origin: ' localhost: 3001 '})); bekerja untuk saya.
allel
11

Cobalah:

const cors = require('cors')

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

}
app.use(cors(corsOptions));
Perisai besi
sumber
6

Jika Anda ingin mengizinkan semua asal dan menjaga kredensial tetap benar, ini bekerja untuk saya:

app.use(cors({
  origin: function(origin, callback){
    return callback(null, true);
  },
  optionsSuccessStatus: 200,
  credentials: true
}));
Squirrl
sumber
@ Slegaitis Haha ya itu sebabnya ia bekerja untuk semua asal tapi tetap kredensial. Saya tidak akan merekomendasikan ini untuk keamanan tetapi tidak berfungsi.
Squirrl
2

(Sunting) Add-on yang direkomendasikan sebelumnya tidak tersedia lagi, Anda dapat mencoba yang lain ini


Untuk tujuan pengembangan di Chrome, menginstal pengaya ini akan menghilangkan kesalahan khusus itu:

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.

Setelah menginstal, pastikan Anda menambahkan pola url Anda Intercepted URLsdengan mengklik ikon AddOn ( CORS , hijau atau merah) dan mengisi kotak teks yang sesuai. Contoh pola URL untuk ditambahkan di sini yang akan berfungsi http://localhost:8080adalah:*://*

eriel marimon
sumber
Saya mendapatkannya setelah menginstalnya, ada ide?
Jalil
Ini berhasil untuk saya. Peringatan jika Anda memiliki add-on serupa lainnya, Anda harus menghapus instalannya sebelum mencoba yang ini.
FilippoG
tolong perbaiki tautan yang rusak
Luk Aron
Sepertinya add on original sudah dihapus, saya menambahkan rekomendasi baru sebagai (Edit) di bagian atas
eriel marimon
1

Ini bekerja untuk saya dalam pengembangan tetapi saya tidak dapat menyarankan bahwa dalam produksi, itu hanya cara berbeda untuk menyelesaikan pekerjaan yang belum disebutkan tetapi mungkin bukan yang terbaik. Pokoknya begini:

Anda bisa mendapatkan asal dari permintaan, lalu menggunakannya di tajuk respons. Begini tampilannya di express:

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

Saya tidak tahu apa yang akan terlihat dengan pengaturan python Anda tetapi itu harus mudah diterjemahkan.

Renaud
sumber
Mozilla Dev Documents mengembangkan gagasan untuk mengubah asal yang diizinkan ke yang dari permintaan. Disarankan untuk menambahkan header respons HTTP 'Vary: Origin' dan domain daftar putih yang diizinkan.
Ramzis