CORS là cơ chế nới lỏng Same-Origin Policy. Cấu hình sai nghĩa là bạn tự tay mở dữ liệu của mình cho site khác đọc.
Sai lầm nguy hiểm nhất — phản chiếu Origin kèm credentials:
// dangerous
res.setHeader('Access-Control-Allow-Origin', req.headers.origin)
res.setHeader('Access-Control-Allow-Credentials', 'true')Bất kỳ site nào cũng gửi được request kèm cookie phiên của nạn nhân và đọc được response. Kết quả tương đương CSRF nhưng còn tệ hơn: kẻ tấn công lấy được cả dữ liệu trả về, không chỉ gây side effect.
Các biến thể sai khác:
- Khớp Origin bằng startsWith/endsWith: https://your-site.com.evil.example hoặc https://evilyour-site.com lọt qua. Phải so khớp chính xác với danh sách cho phép.
- Cho phép null: Origin: null phát sinh từ iframe sandbox, redirect, data: URL — kẻ tấn công tạo được dễ dàng.
- Whitelist toàn bộ subdomain (.your-site.com) khi có subdomain do người dùng kiểm soát hoặc một subdomain cũ bị bỏ hoang (subdomain takeover).
- Dùng cho API nội bộ* — với trình duyệt không gửi credentials, nhưng nếu API tin tưởng theo IP mạng nội bộ thì vẫn rò dữ liệu.
Cấu hình đúng:
const ALLOWED = new Set(['https://app.your-site.com', 'https://admin.your-site.com'])
const origin = req.headers.origin
if (origin && ALLOWED.has(origin)) {
res.setHeader('Access-Control-Allow-Origin', origin)
res.setHeader('Vary', 'Origin') // required so caches do not mix responses
res.setHeader('Access-Control-Allow-Credentials', 'true')
}Hai điểm hay quên: phải thêm Vary: Origin để CDN không cache nhầm header cho origin khác, và CORS không thay thế xác thực — endpoint vẫn phải kiểm tra quyền như thường.