บทความทั้งหมด

ข้อผิดพลาด CORS: เหตุใดเบราว์เซอร์จึงบล็อกการตอบกลับ

ไทยมีชุมชนนักพัฒนา Laravel/PHP ที่แข็งแกร่ง และเฟรมเวิร์กนี้มาพร้อมไฟล์ config/cors.php ตั้งแต่เวอร์ชัน 7 สถานการณ์ที่พบบ่อยคือตั้งค่า 'allowed_origins' => ['*'] ไว้ตอนพัฒนาเพื่อความสะดวก แล้วลืมจำกัดให้แคบลงก่อนขึ้น production มันยังทำงานได้ดีสำหรับคำขอ GET ธรรมดา จนกว่าทีมจะเปิด 'supports_credentials' => true เพื่อใช้ Sanctum ยืนยันตัวตนข้าม subdomain — ตอนนั้นเบราว์เซอร์จะเริ่มปฏิเสธการตอบกลับ เพราะ origin แบบ wildcard ใช้ร่วมกับ credentials ไม่ได้

นโยบาย Same-Origin

โดยค่าเริ่มต้น เบราว์เซอร์บังคับใช้นโยบาย Same-Origin: โค้ด JavaScript จากหน้าที่มาจากออริจินหนึ่ง (โดเมน + โปรโตคอล + พอร์ต) ไม่สามารถอ่านการตอบกลับของคำขอที่ส่งไปยังออริจินอื่นได้ นี่เป็นกลไกความปลอดภัยพื้นฐานที่ป้องกันไม่ให้โค้ดอันตรายในเว็บไซต์หนึ่งขโมยข้อมูลจากอีกเว็บไซต์ที่ผู้ใช้ล็อกอินอยู่

CORS ผ่อนปรนนโยบายนี้อย่างไร

CORS (Cross-Origin Resource Sharing) เป็นชุดของ HTTP headers ที่เซิร์ฟเวอร์อนุญาตอย่างชัดเจนให้ออริจินภายนอกที่ระบุ (หรือทั้งหมด) อ่านการตอบกลับของมันได้ เฮดเดอร์หลักคือ Access-Control-Allow-Origin ซึ่งระบุโดเมนที่ได้รับอนุญาต

กับดัก wildcard บวก credentials

เมื่อคำขอถูกส่งพร้อม credentials: 'include' — ซึ่งจำเป็นสำหรับส่งคุกกี้เซสชันไปยัง API บน subdomain อื่น — เบราว์เซอร์จะปฏิเสธ Access-Control-Allow-Origin: * ในการตอบกลับโดยสิ้นเชิง สเปกห้ามการรวม wildcard origin กับ credentials ไว้อย่างชัดเจน เซิร์ฟเวอร์ต้องส่ง origin ที่ตรงกับผู้ส่งคำขอกลับมาแทน

เหตุใดจึงจำเป็น

  • วินิจฉัยข้อผิดพลาด CORS และหาว่าเฮดเดอร์ใดขาดหายไปบนเซิร์ฟเวอร์อย่างชัดเจน
  • ตรวจจับการตั้งค่า config/cors.php ของ Laravel ที่ยังหลวมเกินไปก่อนขึ้น production
  • เข้าใจความแตกต่างระหว่างคำขอ "แบบง่าย" กับคำขอ preflight (OPTIONS)

CORS ไม่ปกป้องเซิร์ฟเวอร์จากการโจมตี

ความเข้าใจผิดที่พบบ่อยคือคิดว่า CORS เป็นมาตรการความปลอดภัยฝั่งเซิร์ฟเวอร์ — แต่ในความเป็นจริงมันจำกัดแค่สิ่งที่ JavaScript ในเบราว์เซอร์สามารถอ่านได้เท่านั้น ผู้โจมตีที่ใช้ curl, Postman หรือสคริปต์แบ็กเอนด์โดยตรงจะข้าม CORS ไปได้ทั้งหมด เพราะเครื่องมือเหล่านี้ไม่บังคับใช้นโยบาย same-origin CORS ไม่ควรถูกมองว่าเป็นตัวแทนของการยืนยันตัวตนและการให้สิทธิ์ที่แท้จริงบนเซิร์ฟเวอร์

ลองใช้เครื่องมือ