CORS: ไม่สามารถใช้อักขระตัวแทนใน Access-Control-Allow-Origin เมื่อการตั้งค่าสถานะหนังสือรับรองเป็นจริง


296

ฉันมีการตั้งค่าที่เกี่ยวข้อง

เซิร์ฟเวอร์ส่วนหน้า (Node.js, โดเมน: localhost: 3000) <---> แบ็กเอนด์ (Django, Ajax, โดเมน: localhost: 8000)

เบราว์เซอร์ <- webapp <- Node.js (ให้บริการแอป)

เบราว์เซอร์ (webapp) -> Ajax -> Django (ทำหน้าที่ร้องขอ ajax POST)

ตอนนี้ปัญหาของฉันที่นี่คือการตั้งค่า CORS ซึ่ง webapp ใช้ในการโทร Ajax ไปยังเซิร์ฟเวอร์เบื้องหลัง ในโครเมียมฉันได้รับ

ไม่สามารถใช้ wildcard ใน Access-Control-Allow-Origin เมื่อการตั้งค่าสถานะหนังสือรับรองเป็นจริง

ไม่ทำงานกับ firefox เช่นกัน

การตั้งค่า 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();
};

และใน Django ฉันใช้มิดเดิลแวร์นี้ ควบคู่กับสิ่งนี้

แอปพลิเคชันส่งคำขอเป็นเช่นนี้:

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

ดังนั้นคำขอส่วนหัวที่แอพส่งดูเหมือนว่า:

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

และนี่คือหัวข้อการตอบกลับ:

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

ฉันจะไปผิดไหน!

แก้ไข 1: ฉันใช้อยู่chrome --disable-web-securityแต่ตอนนี้ต้องการให้สิ่งต่าง ๆ ใช้งานได้จริง

แก้ไข 2: คำตอบ:

ดังนั้นทางออกสำหรับฉัน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/
)

1
สำหรับฉันมันคือ localhost: 3000 โดยไม่มี http เช่นนี้: CORS_ORIGIN_WHITELIST = ('localhost: 3000',)
Andrei

คุณหมายถึงคุณใช้พัฒนาส่วนหน้าและส่วนหลังในพีซีเครื่องเดียวหรือไม่?
fanhualuojin154873

ส่วนหน้าและส่วนหลังในพีซีต่างกันอย่างไร
fanhualuojin154873

@ixaxaar ทำไมคุณพูดด้วย http ที่เหมาะกับคุณ พวกเราทุกคนใช้งานได้ `` localhost: 3000 '' เท่านั้น
244boy

@ 244boy ใช่จุดไม่httpได้เป็น/ตอนจบ ฉันคิดว่าการละเว้น http อาจใช้งานได้ แต่ฉันไม่ได้ทำงานกับสิ่งนี้มาหลายปีแล้วดังนั้นจึงไม่ทราบว่าใช้งานได้จริงในตอนนี้!
ixaxaar

คำตอบ:


247

นี่เป็นส่วนหนึ่งของความปลอดภัยคุณไม่สามารถทำได้ หากคุณต้องการให้ข้อมูลประจำตัวของคุณแล้วไม่ต้องใช้Access-Control-Allow-Origin *คุณจะต้องระบุโปรโตคอล + โดเมน + พอร์ตที่แน่นอน สำหรับการอ้างอิงดูคำถามเหล่านี้:

  1. การเข้าถึง - การควบคุม - อนุญาต - กำเนิดโดเมนย่อยไวด์การ์ด, พอร์ตและโปรโตคอล
  2. การข้ามทรัพยากรต้นกำเนิดร่วมกับหนังสือรับรอง

นอกจาก*นี้อนุญาตเกินไปและจะเอาชนะการใช้ข้อมูลประจำตัว ดังนั้นการตั้งค่าhttp://localhost:3000หรือhttp://localhost:8000เป็นส่วนหัวอนุญาตให้กำเนิด


45
แต่ถ้ามีมากกว่าหนึ่งโดเมนล่ะ
aroth

13
@aroth คุณสามารถให้รายการโดเมนได้ คำถามที่เกี่ยวข้อง: stackoverflow.com/questions/1653308/…
user568109

13
@ user568109 คุณช่วยอธิบายว่า "นอกจาก*นี้อนุญาตเกินไปและจะใช้ข้อมูลประจำตัวไม่ได้"
Hugo Wood

12
"โดเมนที่ถูกต้อง" คืออะไรหากคำขอมาจากอุปกรณ์พกพาเหมือนกับที่อาจเกิดขึ้นกับ Cordova
Christian

8
@ คริสเตียนเก่า แต่ถ้าใครยังอยากรู้อยากเห็นปัญหานี้เกิดขึ้นเฉพาะกับแอปพลิเคชันที่ทำงานบนเบราว์เซอร์เพราะข้อผิดพลาดนี้เกิดจากเบราว์เซอร์เพราะเหตุผลด้านความปลอดภัย ลูกค้าอื่น ๆ เช่น app มือถือ, บุรุษไปรษณีย์หรือรหัสแบ็กเอนด์อื่น ๆ ที่ใช้โปรแกรม http ขอใช้บริการจะไม่ได้มีปัญหานี้เพื่อให้คุณไม่ต้องกังวลเกี่ยวกับต้นกำเนิดและโดเมนที่แน่นอน
Alisson

32

หากคุณใช้มิดเดิลแวร์ CORS และคุณต้องการส่งwithCredentialบูลีนจริงคุณสามารถกำหนดค่า CORS ดังนี้:

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

16

หากคุณใช้expressคุณสามารถใช้แพ็คเกจcorsเพื่อให้ CORS เป็นเช่นนั้นแทนการเขียนมิดเดิลแวร์ของคุณ

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

app.use(cors());

app.get(function(req,res){ 
  res.send('hello');
});

12
อาตอนนี้มันสะดวกกว่านี้ แต่ผลลัพธ์ก็เหมือนกัน :( BTW ฉันใช้app.use(cors({credentials: true}));
ixaxaar

1
คุณอาจต้องการที่จะมองเข้าไปนี้มิดเดิลแวร์ Django ล ธ ที่มีการทดสอบ
Bulkan

1
งั้นคุณมีมิดเดิ้ล Django สองอัน? ฉันจะใช้django-cors-headerแอพเท่านั้น ตรวจสอบให้แน่ใจว่าคุณเพิ่มlocalhostให้กับCORS_ORIGIN_WHITELISTการตั้งค่าและตั้งCORS_ALLOW_CREDENTIALSเป็นTrue
Bulkan

1
ใช่คนที่พยายามว่าก่อนที่จะไม่มีประโยชน์มีCORS_ORIGIN_ALLOW_ALL = True, CORS_ORIGIN_WHITELIST = ( 'localhost' )และCORS_ALLOW_CREDENTIALS = True ฉันจะได้รับส่วนหัวเหล่านี้: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
หลังจากอ่านเอกสารนี้: github.com/expressjs/corsuse i โดยใช้ config นี้: app.use (cors ({หนังสือรับรอง: จริงต้นกำเนิด: ' localhost: 3001 '})); ทำงานให้ฉัน
อัลลีล


6

หากคุณต้องการอนุญาตต้นกำเนิดทั้งหมดและรักษาข้อมูลรับรองให้ถูกต้องสิ่งนี้ใช้ได้กับฉัน:

app.use(cors({
  origin: function(origin, callback){
    return callback(null, true);
  },
  optionsSuccessStatus: 200,
  credentials: true
}));

@Slegaitis ฮ่าฮ่าใช่นั่นเป็นเหตุผลว่าทำไมจึงเหมาะกับต้นกำเนิดทั้งหมด แต่เก็บรักษาข้อมูลรับรองไว้ ฉันไม่แนะนำให้ใช้เพื่อความปลอดภัย แต่ใช้งานได้
Squirrl

2

(แก้ไข) Add-on ที่แนะนำก่อนหน้านี้ไม่สามารถใช้ได้อีกต่อไปคุณสามารถลองอันนี้ได้


เพื่อการพัฒนาใน Chrome การติดตั้ง ส่วนเสริมนี้จะกำจัดข้อผิดพลาดเฉพาะนั้น:

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.

หลังจากติดตั้งให้แน่ใจว่าคุณเพิ่มรูปแบบ URL ของคุณไปที่Intercepted URLsโดยคลิกที่ไอคอน( CORS , สีเขียวหรือสีแดง) ของ AddOn และกรอกกล่องข้อความที่เหมาะสม ตัวอย่างรูปแบบ URL ที่จะเพิ่มที่นี่ซึ่งจะhttp://localhost:8080ใช้ได้:*://*


ฉันได้รับมันหลังจากติดตั้งแล้วความคิดใด ๆ
Jalil

มันใช้งานได้สำหรับฉัน คำเตือนหากคุณมีส่วนเสริมอื่นที่คล้ายคลึงกันคุณต้องถอนการติดตั้งก่อนลองตัวนี้
FilippoG

โปรดแก้ไขลิงก์ที่ขาด
Luk Aron

ดูเหมือนว่าการเพิ่มเดิมจะถูกลบฉันได้เพิ่มคำแนะนำใหม่เป็น (แก้ไข) ที่ด้านบน
eriel marimon

1

สิ่งนี้ใช้ได้กับฉันในการพัฒนา แต่ฉันไม่สามารถให้คำแนะนำได้ว่าในการผลิตมันเป็นวิธีการทำงานที่ไม่ได้กล่าวถึง แต่อาจไม่ใช่วิธีที่ดีที่สุด อย่างไรก็ตามที่นี่จะไป:

คุณสามารถรับต้นกำเนิดจากคำขอจากนั้นใช้ในส่วนหัวการตอบกลับ นี่คือลักษณะที่แสดง:

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

ฉันไม่รู้ว่าสิ่งใดที่ดูเหมือนกับการตั้งค่าไพ ธ อนของคุณ แต่ควรแปลได้ง่าย


Mozilla Dev Docsขยายความคิดในการเปลี่ยนต้นกำเนิดที่อนุญาตเป็นหนึ่งจากการร้องขอ ขอแนะนำให้เพิ่มส่วนหัวการตอบสนอง HTTP 'Vary: Origin' และอนุญาตรายการโดเมนที่อนุญาต
Ramzis
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.