หากคุณกำลังพัฒนาเว็บแอปที่ต้องเรียก API ข้ามโดเมน แล้วเจอข้อความประมาณว่า “Access to fetch at ‘https://api.example.com/data’ from origin ‘https://yourdomain.com’ has been blocked by CORS policy” อย่าเพิ่งรีบตกใจไป เพราะนี่คือปัญหาสุดคลาสสิกที่เรียกว่า CORS หรือ Cross-Origin Resource Sharing ซึ่งในบทความนี้เราจะพาไปทำความรู้จักและเข้าใจมันแบบง่าย ๆ กัน
CORS คืออะไร?
CORS ย่อมาจาก Cross-Origin Resource Sharing คือกลไกความปลอดภัยของเว็บเบราว์เซอร์ที่ใช้ควบคุมการเข้าถึงทรัพยากร (เช่น API, ไฟล์ JSON, รูปภาพ ฯลฯ) ระหว่างต้นทาง (Origin) อื่น ว่าอนุญาตให้เว็บไซต์อื่นมาขอข้อมูลจากตัวเองหรือไม่ โดยต้นทาง (Origin) ในมุมมองของเว็บเบราว์เซอร์จะประกอบไปด้วย 3 ส่วน ได้แก่ Protocol, Hostname และ Port
ตัวอย่างของ Origin
URL | Origin |
---|---|
https://example.com | https://example.com:443 |
http://example.com | http://example.com:80 |
https://api.example.com | คนละ origin เพราะ subdomain ต่างกัน |
https://example.com:3000 | คนละ origin เพราะ port ต่างกัน |
ดังนั้น ถ้าเว็บของเรารันที่ https://myapp.com แล้วเรียก API จาก https://api.myapp.com ก็ถือว่าเป็น cross-origin แล้ว
ทำไมถึงต้องมี CORS?
สาเหตุหลักที่ CORS ถูกพัฒนาขึ้นมา ก็เพื่อเพิ่มความปลอดภัยในการใช้งานเว็บไซต์ โดยเฉพาะการป้องกันภัยคุกคามที่อาจเกิดจากเว็บภายนอก เช่น การขโมยข้อมูลส่วนตัว การโจมตีแบบ Cross-Site Request Forgery (CSRF) หรือการแอบใช้ session/cookie ของผู้ใช้โดยไม่ได้รับอนุญาต ทางเบราว์เซอร์จึงมีระบบป้องกันไม่ให้เว็บไซต์ใด ๆ สามารถเรียกดูหรือใช้งานข้อมูลจากอีกเว็บหนึ่งได้ทันที เว้นเสียแต่ว่าเว็บปลายทางจะระบุชัดเจนว่าอนุญาต
ยกตัวอย่างเช่น มีผู้ใช้ล็อกอินเข้าเว็บธนาคารที่ bank.com แล้วอยู่ ๆ ก็มีเว็บแปลก ๆ ที่ hacker.com แอบฝัง JavaScript ไว้ และพยายามขอข้อมูลจาก bank.com โดยถ้าไม่มี CORS คอยกรองไว้ แฮกเกอร์อาจดูดข้อมูลสำคัญของผู้ใช้ไปได้เลย
การทำงานของ CORS (เบื้องหลัง)
สมมุติว่าเว็บไซต์ A (https://app-client.com) พยายามเรียก API จากเว็บไซต์ B (https://api-server.com) ซึ่งเป็น Cross-Origin โดยเมื่อเบราว์เซอร์เจอการร้องขอดังกล่าว จะเริ่มดำเนินการตามขั้นตอนต่อไปนี้
1. เบราว์เซอร์ส่งคำขอ HTTP request ไปที่ https://api-server.com
2. ฝั่ง API Server จะตรวจสอบและตอบกลับ Header ของคำขอ เช่น
เพิ่ม app-client.com ให้เข้าถึงได้
Access-Control-Allow-Origin: https://app-client.com
หรือยอมให้ทุก Origin เข้าถึงได้ (ไม่แนะนำกับข้อมูลที่ต้องการความปลอดภัย)
Access-Control-Allow-Origin: *
3. หากเบราว์เซอร์ไม่เห็น Header เหล่านี้ เบราว์เซอร์จะดำเนินการบล็อกคำขอนั้นทันที
การเปิดใช้งาน CORS
ฝั่งเซิร์ฟเวอร์
ตัวอย่างใน Node.js (Express)
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({
origin: 'https://yourdomain.com' // หรือใช้ '*' ถ้าไม่ซีเรียส
}));
ตัวอย่างใน PHP
const express = require('express');
const cors = require('cors');
const app = express();
app.use(cors({
origin: 'https://yourdomain.com' // หรือใช้ '*' ถ้าไม่ซีเรียส
}));
ตัวอย่างใน nginx
header("Access-Control-Allow-Origin: https://yourdomain.com");
ฝั่ง Frontend
ไม่มีอะไรต้องตั้งค่าเป็นพิเศษ แค่ตั้งให้ส่ง request ตามปกติ
fetch('https://api.example.com/data')
.then(res => res.json())
.then(data => console.log(data));
ถ้ามี Header พิเศษ เช่น Authorization หรือ Content-Type ที่ไม่ใช่ค่าเริ่มต้น เบราว์เซอร์จะส่ง preflight request (OPTIONS) ก่อน เพื่อเช็กว่าฝั่ง server อนุญาตมั้ย
ปัญหาและความเข้าใจผิดที่พบได้บ่อยเกี่ยวกับ CORS
- ปัญหา Access-Control-Allow-Origin missing → เกิดจาก Server ไม่ได้ตั้ง header ตอบกลับ
- ปัญหา CORS policy: No ‘Access-Control-Allow-Origin’ header → เกิดจากฝั่งเบราว์เซอร์บล็อกทันที
- ❌ คิดว่าเป็นปัญหาจากฝั่ง client → ✅ เป็นเรื่องของ server ที่ต้องอนุญาตเท่านั้น.
- ❌ คิดว่าใช้ * กับ credential (cookie/token) ได้ → ✅ ต้องระบุ origin ให้ชัดเจน
จัดการ CORS ยังไงให้เวิร์ก
- อย่าใช้ * กับ API ที่ต้องมี Auth (เพราะจะใช้ร่วมกับ credentials ไม่ได้)
- ถ้าใช้ fetch แบบมี cookie หรือ token ต้องตั้ง
fetch(url, {
credentials: 'include'
})
แล้วฝั่ง server ต้องตอบด้วย
Access-Control-Allow-Credentials: true
- ระวัง environment ที่ต่างกัน (เช่น dev, staging, prod) โดยต้องกำหนด Origin ให้ถูกต้อง
สรุปง่าย ๆ คือ CORS เปรียบเสมือนการ์ดรักษาความปลอดภัยของเว็บเบราว์เซอร์ ที่จะคอยถาม server ว่าเว็บนี้จะเข้ามาเอาข้อมูลได้หรือไม่ ถ้า server ไม่ตอบหรือไม่อนุญาตอย่างชัดเจน เบราว์เซอร์ก็จะไม่ให้ข้อมูลนั้นถูกใช้งานในฝั่ง client เลย เป็นการป้องกันแบบเชิงรุกที่ช่วยให้ผู้ใช้งานเว็บปลอดภัยมากขึ้น