CORS คืออะไร? ทำไมต้องตั้งค่า?
สวัสดีครับ! กลับมาพบกันอีกครั้งกับบทเรียนสร้าง API ด้วย PHP สำหรับผู้เริ่มต้น ในบทที่แล้ว เราได้เรียนรู้เกี่ยวกับการใช้ Middleware เพื่อจัดการ Authentication และ Authorization ไปแล้ว ในบทนี้ เราจะมาทำความเข้าใจเกี่ยวกับ CORS (Cross-Origin Resource Sharing) ซึ่งเป็นอีกหนึ่งเรื่องสำคัญที่ต้องคำนึงถึงเมื่อสร้าง API โดยเฉพาะอย่างยิ่งเมื่อ API ของเราถูกเรียกใช้งานจากเว็บไซต์หรือแอปพลิเคชันที่อยู่คนละโดเมนกัน
CORS คืออะไร?
CORS (Cross-Origin Resource Sharing) คือ กลไกที่อนุญาตให้เว็บเพจที่รันอยู่บนโดเมนหนึ่ง (Origin) สามารถเข้าถึง Resources จากโดเมนอื่นได้ (Cross-Origin Request) โดยปกติแล้ว Browser จะมีนโยบายรักษาความปลอดภัยที่เรียกว่า Same-Origin Policy ซึ่งป้องกันไม่ให้ JavaScript ที่รันอยู่บนเว็บเพจหนึ่งสามารถทำการ Request ไปยังโดเมนอื่นได้โดยตรง เพื่อป้องกันการโจมตีแบบ Cross-Site Scripting (XSS) และการขโมยข้อมูล
Same-Origin Policy คืออะไร? ลองนึกภาพว่าคุณกำลังเข้าสู่ระบบธนาคารออนไลน์บนเว็บไซต์ bank.com หากไม่มี Same-Origin Policy เว็บไซต์อื่น เช่น evil.com อาจจะสามารถใช้ JavaScript ดึงข้อมูลส่วนตัวของคุณจาก bank.com ได้ ซึ่งเป็นเรื่องที่อันตรายมาก Same-Origin Policy จึงถูกสร้างขึ้นมาเพื่อป้องกันเหตุการณ์แบบนี้ โดยจะอนุญาตให้ JavaScript สามารถเข้าถึง Resources ได้ก็ต่อเมื่อ Origin ของเว็บเพจที่รัน JavaScript นั้นตรงกับ Origin ของ Resource ที่ต้องการเข้าถึงเท่านั้น
Origin คืออะไร? Origin ประกอบไปด้วยสามส่วนหลักๆ คือ:
- Protocol: เช่น
httpหรือhttps - Hostname: เช่น
example.com - Port: เช่น
80หรือ443(ถ้าไม่ได้ระบุ Port จะใช้ Port Default ของ Protocol นั้นๆ)
ดังนั้น http://example.com:8080 และ https://example.com ถือว่าเป็น Origin ที่แตกต่างกัน แม้ว่าจะเป็น Hostname เดียวกันก็ตาม
แล้วทำไมถึงต้องมี CORS ในเมื่อ Same-Origin Policy ก็ดูเหมือนจะปลอดภัยดีอยู่แล้ว? คำตอบคือ ในโลกของการพัฒนา Web Application สมัยใหม่ เรามักจะแยกส่วน Front-end (ส่วนที่ผู้ใช้มองเห็น) และ Back-end (ส่วนที่จัดการข้อมูลและ Logic) ออกจากกัน โดย Front-end อาจจะรันอยู่บนโดเมนหนึ่ง และ Back-end (API) รันอยู่บนอีกโดเมนหนึ่ง หาก Browser บังคับใช้ Same-Origin Policy อย่างเคร่งครัด Front-end ก็จะไม่สามารถเรียกใช้งาน API จาก Back-end ได้เลย ซึ่งจะทำให้การพัฒนา Web Application เป็นไปได้ยากมาก
CORS จึงถูกสร้างขึ้นมาเพื่อเป็นกลไกที่ช่วยให้ Browser สามารถตัดสินใจได้ว่า จะอนุญาตให้ Cross-Origin Request นั้นๆ ทำงานได้หรือไม่ โดยอาศัย HTTP Headers ที่ Server ส่งกลับมา
ทำไมต้องตั้งค่า CORS?
ถ้า API ของคุณถูกเรียกใช้งานจาก Front-end ที่อยู่บนโดเมนอื่น คุณจะต้องตั้งค่า CORS อย่างถูกต้อง เพื่อให้ Browser อนุญาตให้ Front-end สามารถเข้าถึง API ของคุณได้ หากไม่ได้ตั้งค่า CORS Browser จะแสดง Error ประมาณว่า "Cross-Origin Request Blocked" และ Request จะถูก Block ไม่ให้ส่งไปถึง Server
กรณีใช้งานจริง:
สมมติว่าคุณมี API ที่รันอยู่บน api.example.com และ Front-end ของคุณรันอยู่บน app.example.com หาก Front-end พยายามที่จะส่ง Request ไปยัง API โดยไม่ได้ตั้งค่า CORS ที่ Server Browser จะ Block Request นั้น และแสดง Error ใน Console ของ Browser
// ตัวอย่างโค้ด JavaScript ที่พยายามเรียก API
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
ข้อผิดพลาดที่พบบ่อย:
- ลืมตั้งค่า CORS: นี่เป็นข้อผิดพลาดที่พบบ่อยที่สุด คือลืมตั้งค่า CORS Headers ที่ Server ทำให้ Browser Block Request
- ตั้งค่า CORS ไม่ถูกต้อง: เช่น อนุญาตเฉพาะบาง Origin แต่ Front-end ของคุณไม่ได้อยู่ใน Origin ที่อนุญาต
- ไม่ได้ Handle Preflight Request: สำหรับ Request บางประเภท (เช่น POST ที่มี Content-Type เป็น
application/json) Browser จะส่ง Preflight Request ก่อนที่จะส่ง Request จริง คุณต้อง Handle Preflight Request ที่ Server ด้วย
Preflight Request คืออะไร?
Preflight Request คือ HTTP Request ที่ Browser ส่งไปยัง Server ก่อนที่จะส่ง Cross-Origin Request จริง เพื่อตรวจสอบว่า Server อนุญาตให้ Cross-Origin Request นั้นๆ ทำงานได้หรือไม่ Preflight Request จะใช้ HTTP Method OPTIONS และมี Headers ที่ระบุรายละเอียดเกี่ยวกับ Cross-Origin Request ที่กำลังจะส่ง เช่น Access-Control-Request-Method และ Access-Control-Request-Headers
Server จะตอบกลับ Preflight Request ด้วย HTTP Status Code 200 OK และ Headers ที่ระบุว่าอนุญาตให้ Cross-Origin Request นั้นๆ ทำงานได้หรือไม่ เช่น Access-Control-Allow-Origin, Access-Control-Allow-Methods และ Access-Control-Allow-Headers
ตัวอย่าง Preflight Request:
OPTIONS /data HTTP/1.1
Host: api.example.com
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Content-Type
ตัวอย่าง Response จาก Server (อนุญาต):
HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 86400
คำอธิบาย Headers:
Access-Control-Allow-Origin: ระบุ Origin ที่ได้รับอนุญาตให้เข้าถึง Resource นี้ (สามารถใช้*เพื่ออนุญาตทุก Origin แต่ไม่แนะนำใน Production)Access-Control-Allow-Methods: ระบุ HTTP Methods ที่ได้รับอนุญาต (เช่นGET,POST,PUT,DELETE,OPTIONS)Access-Control-Allow-Headers: ระบุ Headers ที่ Client สามารถส่งได้Access-Control-Max-Age: ระบุระยะเวลาที่ Browser สามารถ Cache ผลลัพธ์ของ Preflight Request ได้ (เป็นวินาที)
ในบทถัดไป เราจะมาเรียนรู้วิธีการตั้งค่า CORS Headers ใน PHP เพื่อให้ API ของเราสามารถถูกเรียกใช้งานจาก Front-end ที่อยู่บนโดเมนอื่นได้อย่างถูกต้อง อย่าลืมติดตามกันนะครับ!