app.A.comfetch('B/api')api.B.comA-C-A-O: A.comOPTIONS preflightCORS allow → JS may readrequest always reaches server; response visibility is gated

การแบ่งปันทรัพยากรข้ามแหล่งกำเนิด

11 นาทีอ่านเทคโนโลยีเว็บ

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

เนื้อหาบทความฉบับเต็มมีให้เป็นภาษาอังกฤษด้านล่าง

Cross-Origin Resource Sharing (CORS) เป็นกลไกของเบราว์เซอร์ที่ช่วยให้เซิร์ฟเวอร์ประกาศว่าต้นทางอื่นใดที่ได้รับอนุญาตให้เข้าถึงการตอบกลับ เมื่อรวมกับนโยบายต้นทางเดียวกัน (ค่าเริ่มต้นของเบราว์เซอร์คือ "อย่าให้ต้นทางอ่านคำตอบของอีกต้นหนึ่ง") CORS จัดเตรียมกลไกสำหรับการผ่อนคลายแบบเลือก

นโยบายต้นทางเดียวกันก่อน

ตามค่าเริ่มต้น เบราว์เซอร์จะบังคับใช้ว่า JavaScript ที่ทำงานบนต้นทาง A ไม่สามารถอ่านคำตอบจากต้นทาง B ได้ นี่คือนโยบายต้นทางเดียวกัน "Origin" หมายถึง Scheme + Host + Port; https://a.example.com และ https://b.example.com มีต้นกำเนิดที่แตกต่างกัน

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

สิ่งที่ CORS เพิ่ม

กรณีการใช้งานที่ถูกต้องตามกฎหมายจำนวนมากจำเป็นต้องมีการอ่านแบบข้ามต้นทาง — แบบอักษรจาก CDN, การเรียก API จากส่วนหน้าไปยังส่วนหลังบนโดเมนอื่น, วิดเจ็ตโซเชียลมีเดียแบบฝัง CORS ให้เซิร์ฟเวอร์ที่ตอบสนองพูดอย่างชัดเจนว่า "ใช่ ต้นทางอื่นนี้สามารถอ่านคำตอบของฉันได้"

เซิร์ฟเวอร์มีส่วนหัว Access-Control-Allow-Origin ในการตอบกลับ เบราว์เซอร์จะตรวจสอบ: หากต้นทางที่ร้องขอตรงกับค่า (หรือเป็นไวด์การ์ด *) การตอบสนองจะถูกเปิดเผยต่อ JavaScript ถ้าไม่เช่นนั้น เบราว์เซอร์จะบล็อกไม่ให้ JavaScript อ่านมัน คำขอ ยังคงดำเนินต่อไป เซิร์ฟเวอร์ ยังคงได้รับและประมวลผล อยู่ - มีเพียงการมองเห็น JavaScript เท่านั้นที่ถูกจำกัด

คำขอแบบธรรมดาเทียบกับคำขอที่บินล่วงหน้า

สำหรับคำขอ "แบบง่าย" (GET, HEAD, POST พร้อมประเภทเนื้อหาพื้นฐาน) เบราว์เซอร์จะส่งคำขอและตรวจสอบ CORS ในการตอบสนอง หาก CORS ไม่อนุญาต JavaScript จะไม่สามารถอ่านได้

สำหรับคำขอ "ซับซ้อน" (PUT, DELETE, ส่วนหัวที่กำหนดเอง, ประเภทเนื้อหา JSON) เบราว์เซอร์จะส่งคำขอ preflight OPTIONS ก่อน โดยถามว่า "ต้นทาง X สามารถส่งคำขอนี้ให้คุณได้หรือไม่" เซิร์ฟเวอร์ตอบสนองด้วยวิธีการและส่วนหัวที่อนุญาต เฉพาะเมื่อได้รับการอนุมัติเท่านั้นที่เบราว์เซอร์จะส่งคำขอจริง

// Preflight
ตัวเลือก /api/ผู้ใช้ HTTP/1.1
ที่มา: https://app.example.com
การเข้าถึงการควบคุมการร้องขอวิธีการ: ลบ
Access-Control-Request-Headers: การอนุญาต

// การตอบสนองของเซิร์ฟเวอร์
HTTP/1.1 204 ไม่มีเนื้อหา
การควบคุมการเข้าถึง-อนุญาต-แหล่งกำเนิด: https://app.example.com
Access-Control-Allow-Methods: ลบ, GET, POST
Access-Control-Allow-Headers: การอนุญาต, ประเภทเนื้อหา
การควบคุมการเข้าถึง-อายุสูงสุด: 86400

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

Credentials และ CORS

Cookies และส่วนหัวการตรวจสอบสิทธิ์ HTTP ("ข้อมูลประจำตัว") จะไม่ถูกส่งไป คำขอข้ามต้นทางตามค่าเริ่มต้น หากต้องการรวมไว้ JavaScript ต้องขอ:

fetch('https://api.example.com/data', { credentials: 'include' })

และเซิร์ฟเวอร์จะต้องตอบสนองด้วย Access-Control-Allow-Credentials: true และต้นทางเฉพาะ (ไม่ใช่ wildcard *) ใน Access-Control-Allow-Origin นี่คือ gotcha ทั่วไป: Access-Control-Allow-Origin: * + credentials = none works.

ความเข้าใจผิดทั่วไปของ CORS

  • CORS ไม่ใช่คุณลักษณะด้านความปลอดภัยสำหรับเซิร์ฟเวอร์ คำขอไปถึงเซิร์ฟเวอร์โดยไม่คำนึงถึง CORS เบราว์เซอร์บล็อก JavaScript จาก reading การตอบสนอง เซิร์ฟเวอร์ยังต้องตรวจสอบสิทธิ์และอนุญาต
  • CORS ใช้ไม่ได้กับคำขอทั้งหมด คำขอที่มีต้นกำเนิดเดียวกันไม่ทริกเกอร์ CORS คำขอแบบเซิร์ฟเวอร์ต่อเซิร์ฟเวอร์ไม่ได้ทำเช่นกัน ระหว่างเบราว์เซอร์ถึงเซิร์ฟเวอร์เป็นที่เดียวที่ CORS อาศัยอยู่
  • ไวด์การ์ด * เป็นอันตรายเมื่อรวมกับคุกกี้ บทช่วยสอนจำนวนมากแนะนำ Access-Control-Allow-Origin: * เป็นการแก้ไขด่วน สำหรับ API สาธารณะที่ไม่มีข้อมูลรับรอง ก็ไม่เป็นไร สำหรับสิ่งใดก็ตามที่มีการตรวจสอบสิทธิ์ ใช้งานไม่ได้ ข้อผิดพลาด
  • CORS เป็นปัญหาฝั่งเซิร์ฟเวอร์ เมื่อคุณเห็นข้อผิดพลาด CORS ในคอนโซลของเบราว์เซอร์ การแก้ไขจะอยู่ที่เซิร์ฟเวอร์ที่ตอบสนอง ไม่ใช่ในโค้ดที่ร้องขอ

CORS กับ CSRF

สับสนได้ง่าย CORS ควบคุมสิ่งที่เบราว์เซอร์เปิดเผยต่อ JavaScript CSRF (ดูบทความ CSRF ของเรา ) เป็นเรื่องเกี่ยวกับว่าเบราว์เซอร์ส่งคำขอเลยหรือไม่ CORS ไม่ได้ป้องกัน CSRF — สามารถส่งและประมวลผลคำขอได้แม้ว่า JavaScript จะไม่เห็นการตอบสนองก็ตาม

สำหรับ API ที่เปลี่ยนแปลงสถานะที่ใช้คุกกี้ โทเค็น CSRF หรือคุกกี้ SameSite ยังคงจำเป็นต้องใช้ CORS ไม่ได้แทนที่สิ่งเหล่านี้

แคช preflight

Preflight การตอบสนองสามารถแคชได้ผ่าน Access-Control-Max-Age อายุสูงสุดที่ยาว (24+ ชั่วโมง) ช่วยลดค่าใช้จ่าย — ชุดค่าผสมที่แตกต่างกัน (วิธีการ, URL, ส่วนหัว) จะไม่แสดงล่วงหน้าอีกครั้งจนกว่าจะหมดอายุ อายุสูงสุดที่สั้นสามารถซ้อนเวลาแฝงที่มีนัยสำคัญได้

รูปแบบ CORS ทั่วไปใน 2026

  • Public APIs: Access-Control-Allow-Origin: * สำหรับตำแหน่งข้อมูลที่ไม่มี การตรวจสอบสิทธิ์
  • Authenticated APIs: สะท้อนกลับการเรียกใช้ Origin หากอยู่ในรายการที่อนุญาต โดยมี Access-Control-Allow-Credentials: true.
  • SaaS APIs: per-customer allowance-lists ที่กำหนดค่าโดย ลูกค้า
  • JS การนำส่ง SDK: ไฟล์คงที่พร้อม CORS แบบกว้าง ซึ่งมักจะเป็นรูปแบบ Public-API

คำถามที่พบบ่อย

เหตุใดการดึงข้อมูลของฉันจึงล้มเหลวโดยมีข้อผิดพลาด CORS
เซิร์ฟเวอร์ที่คุณเรียกใช้ไม่มีส่วนหัว Access-Control-Allow-Origin ที่เหมาะสมสำหรับต้นทางของคุณ จำเป็นต้องกำหนดค่าเซิร์ฟเวอร์เพื่ออนุญาตคุณ หรือคุณต้องเรียกเซิร์ฟเวอร์จากต้นทางเดียวกัน (โดยทั่วไปจะผ่านทางพร็อกซีแบ็กเอนด์)
ฉันสามารถข้าม CORS ในฐานะนักพัฒนาได้หรือไม่
ไม่ จากโค้ดของคุณเองในเบราว์เซอร์ มันถูกบังคับใช้โดยเบราว์เซอร์ จากเซิร์ฟเวอร์ของคุณเอง (โค้ดแบ็กเอนด์) ได้ เนื่องจาก CORS ใช้ไม่ได้กับคำขอแบบเซิร์ฟเวอร์ถึงเซิร์ฟเวอร์ วิธีแก้ปัญหาทั่วไปคือพร็อกซีแบ็กเอนด์: ส่วนหน้าของคุณเรียกแบ็กเอนด์ของคุณ แบ็กเอนด์ของคุณเรียก API บุคคลที่สาม
CORS ปกป้อง API ของฉันหรือไม่
ไม่ใช่โดยตรง. API สามารถเข้าถึงได้โดยไม่คำนึงถึง CORS — เบราว์เซอร์ยังคงส่งคำขอ การป้องกันคือ JavaScript บนไซต์อื่นไม่สามารถอ่านคำตอบได้ หากต้องการปกป้อง API จริงๆ ให้ใช้การรับรองความถูกต้องและการอนุญาตบนเซิร์ฟเวอร์
ฉันควรใช้ Access-Control-Allow-Origin: *?
สำหรับ API สาธารณะที่ไม่ยอมรับข้อมูลประจำตัวเท่านั้น สำหรับสิ่งใดก็ตามที่มีคุกกี้หรือส่วนหัวการอนุญาต ให้ใช้ต้นทางที่เฉพาะเจาะจงหรือสะท้อนการเรียกต้นทาง (พร้อมการตรวจสอบความถูกต้อง) เบราว์เซอร์ไม่อนุญาตให้ใช้ Wildcard + ข้อมูลรับรอง
เหตุใด CORS จึงทำการบินล่วงหน้าเพียงบางคำขอเท่านั้น
คำขอทั่วไป (GET, HEAD, POST ที่มีประเภทเนื้อหาพื้นฐานและไม่มีส่วนหัวที่กำหนดเอง) ได้รับการยกเว้น คำขอเหล่านี้เทียบเท่ากับสิ่งที่รูปแบบ HTML สามารถทำได้ก่อนที่จะมี CORS คำขอที่ซับซ้อนไม่มีรูปแบบแอนะล็อกของ HTML ดังนั้นจึงร้องขอล่วงหน้าเพื่อให้เซิร์ฟเวอร์มีโอกาสปฏิเสธก่อนที่จะเปลี่ยนสถานะ
อธิบาย CORS: เบราว์เซอร์ตัดสินใจอย่างไรเมื่ออนุญาตคำขอข้ามแหล่งกำเนิด