กลไกการแชร์ทรัพยากรข้ามโดเมน (CORS)

Mariko Kosaka

เผยแพร่เมื่อ: 5 พฤศจิกายน 2018

นโยบายแหล่งที่มาเดียวกันของเบราว์เซอร์จะบล็อกการอ่านทรัพยากรจากแหล่งที่มาอื่น กลไกนี้จะหยุดไม่ให้เว็บไซต์ที่เป็นอันตรายอ่านข้อมูลของเว็บไซต์อื่น แต่ก็ป้องกันการใช้งานที่ถูกต้องด้วย

เว็บแอปสมัยใหม่มักต้องการรับทรัพยากรจากแหล่งที่มาอื่น เช่น ดึงข้อมูล JSON จากโดเมนอื่น หรือโหลดรูปภาพจาก เว็บไซต์อื่นลงในองค์ประกอบ <canvas> ทรัพยากรเหล่านี้อาจเป็นทรัพยากรสาธารณะที่ทุกคนควรจะอ่านได้ แต่นโยบายแหล่งที่มาเดียวกันจะบล็อกการใช้งาน นักพัฒนาแอปจึงใช้โซลูชันชั่วคราว เช่น JSONP มาโดยตลอด

กลไกการแชร์ทรัพยากรข้ามโดเมน (CORS) แก้ไขปัญหานี้ด้วยวิธีที่ได้มาตรฐาน การเปิดใช้ CORS จะช่วยให้เซิร์ฟเวอร์บอกเบราว์เซอร์ได้ว่าสามารถใช้แหล่งที่มาเพิ่มเติมได้

คำขอทรัพยากรทำงานอย่างไรบนเว็บ

คำขอของไคลเอ็นต์และการตอบกลับของเซิร์ฟเวอร์

เบราว์เซอร์และเซิร์ฟเวอร์สามารถแลกเปลี่ยนข้อมูลผ่านเครือข่ายโดยใช้ Hypertext Transfer Protocol (HTTP) HTTP กำหนดกฎการสื่อสารระหว่างผู้ขอและผู้ตอบ รวมถึงข้อมูลที่จำเป็นในการรับทรัพยากร

ส่วนหัว HTTP จะเจรจาการแลกเปลี่ยนข้อความระหว่างไคลเอ็นต์กับเซิร์ฟเวอร์ และใช้เพื่อกำหนดสิทธิ์เข้าถึง ทั้งคำขอของเบราว์เซอร์และข้อความตอบกลับของเซิร์ฟเวอร์จะแบ่งออกเป็น ส่วนหัว และ เนื้อความ

ข้อมูลเกี่ยวกับข้อความ เช่น ประเภทของข้อความหรือการเข้ารหัสของข้อความ ส่วนหัวอาจมี ข้อมูลหลากหลายรูปแบบ ที่แสดงเป็นคู่คีย์-ค่า ส่วนหัวของคำขอและส่วนหัวการตอบกลับจะมีข้อมูลที่แตกต่างกัน

ตัวอย่างส่วนหัวของคำขอ

Accept: text/html
Cookie: Version=1

ส่วนหัวนี้เทียบเท่ากับการพูดว่า "ฉันต้องการรับ HTML ในการตอบกลับ นี่คือคุกกี้ที่ฉันมี"

ตัวอย่างส่วนหัวการตอบกลับ

Content-Encoding: gzip
Cache-Control: no-store

ส่วนหัวนี้เทียบเท่ากับการพูดว่า "ข้อมูลในการตอบกลับนี้เข้ารหัสด้วย gzip อย่าแคชข้อมูลนี้"

เนื้อความ

ตัวข้อความเอง ซึ่งอาจเป็นข้อความธรรมดา ไบนารีรูปภาพ JSON HTML หรือรูปแบบอื่นๆ อีกมากมาย

CORS ทำงานอย่างไร

นโยบายแหล่งที่มาเดียวกันจะบอกให้เบราว์เซอร์บล็อกคำขอแบบข้ามต้นทาง เมื่อคุณต้องการทรัพยากรสาธารณะจากแหล่งที่มาอื่น เซิร์ฟเวอร์ที่ให้บริการทรัพยากรจะบอกเบราว์เซอร์ว่าแหล่งที่มาที่ส่งคำขอสามารถเข้าถึงทรัพยากรได้ เบราว์เซอร์จะจดจำและอนุญาตให้แชร์ทรัพยากรแบบข้ามต้นทางสำหรับทรัพยากรนั้น

ขั้นตอนที่ 1: คำขอของไคลเอ็นต์ (เบราว์เซอร์)

เมื่อเบราว์เซอร์ส่งคำขอข้ามแหล่งที่มา เบราว์เซอร์จะเพิ่มส่วนหัว Origin ที่มีแหล่งที่มาปัจจุบัน (สคีม โฮสต์ และพอร์ต)

ขั้นตอนที่ 2: การตอบกลับของเซิร์ฟเวอร์

เมื่อเซิร์ฟเวอร์เห็นส่วนหัวนี้และต้องการอนุญาตให้เข้าถึง เซิร์ฟเวอร์จะเพิ่มส่วนหัว Access-Control-Allow-Origin ในการตอบกลับเพื่อระบุแหล่งที่มาที่ส่งคำขอ (หรือ * เพื่ออนุญาตแหล่งที่มาทั้งหมด)

ขั้นตอนที่ 3: เบราว์เซอร์ได้รับการตอบกลับ

เมื่อเบราว์เซอร์เห็นการตอบกลับนี้ที่มีส่วนหัว Access-Control-Allow-Origin ที่เหมาะสม เบราว์เซอร์จะแชร์ข้อมูลการตอบกลับกับเว็บไซต์ของไคลเอ็นต์

แชร์ข้อมูลเข้าสู่ระบบด้วย CORS

โดยปกติแล้ว CORS จะใช้สำหรับคำขอที่ไม่ระบุตัวตน ซึ่งจะไม่ระบุตัวตนของผู้ขอ เนื่องจากเหตุผลด้านความเป็นส่วนตัว หากต้องการส่งคุกกี้เมื่อใช้ CORS ซึ่งระบุตัวตนของผู้ส่งได้ คุณต้องเพิ่มส่วนหัวเพิ่มเติมในคำขอและการตอบกลับ

ส่งคำขอ

เพิ่ม credentials: 'include' ลงในตัวเลือกการดึงข้อมูลตามตัวอย่างต่อไปนี้ ซึ่งจะรวมคุกกี้ไว้ในคำขอ ดังนี้

fetch('https://example.com', {
  mode: 'cors',
  credentials: 'include'
})

การตอบกลับ

ต้องตั้งค่า Access-Control-Allow-Origin เป็นแหล่งที่มาที่เฉพาะเจาะจง (ไม่มีไวลด์การ์ดโดยใช้ *) และต้องตั้งค่า Access-Control-Allow-Credentials เป็น true

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true

คำขอ Preflight สำหรับการเรียก HTTP ที่ซับซ้อน

เมื่อเว็บแอปส่งคำขอ HTTP ที่ซับซ้อน เบราว์เซอร์จะเพิ่ม คำขอ Preflight ที่จุดเริ่มต้นของห่วงโซ่คำขอ

ข้อกำหนด CORS กำหนด คำขอที่ซับซ้อน ไว้ดังนี้

  • คำขอที่ใช้เมธอดอื่นนอกเหนือจาก GET, POST หรือ HEAD
  • คำขอที่มีส่วนหัวอื่นนอกเหนือจาก Accept, Accept-Language หรือ Content-Language
  • คำขอที่มีส่วนหัว Content-Type อื่นนอกเหนือจาก application/x-www-form-urlencoded, multipart/form-data หรือ text/plain

เบราว์เซอร์จะสร้างคำขอ Preflight ที่จำเป็นโดยอัตโนมัติและส่งคำขอดังกล่าวก่อนข้อความคำขอจริง คำขอ Preflight เป็นคำขอ OPTIONS เช่น ตัวอย่างต่อไปนี้

OPTIONS /data HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: DELETE

ในฝั่งเซิร์ฟเวอร์ แอปที่ได้รับคำขอจะตอบกลับคำขอ Preflight ด้วยข้อมูลเกี่ยวกับเมธอดที่แอปพลิเคชันยอมรับจากแหล่งที่มานี้

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, DELETE, HEAD, OPTIONS

การตอบกลับของเซิร์ฟเวอร์อาจมีส่วนหัว Access-Control-Max-Age เพื่อระบุระยะเวลาเป็นวินาทีในการแคชผลลัพธ์ Preflight ซึ่งจะช่วยให้ไคลเอ็นต์ส่งคำขอที่ซับซ้อนหลายรายการได้โดยไม่ต้องส่งคำขอ Preflight ซ้ำ