Appearance
CORS
CORS (Cross-Origin Resource Sharing) là lỗi/khái niệm gần như mọi người mới đều gặp đầu tiên khi bắt đầu gọi API từ frontend: browser chặn request, console báo blocked by CORS policy, dù gọi thẳng bằng Postman/curl thì lại chạy bình thường. Hiểu đúng CORS giúp không hoảng khi gặp lỗi này, và không "tắt bừa" theo cách làm lộ lỗ hổng bảo mật.
Same-origin policy — vì sao CORS tồn tại
Trình duyệt mặc định áp dụng same-origin policy: 1 trang web ở origin A (ví dụ https://app.example.com) không được phép đọc response từ 1 origin B khác (ví dụ https://api.example.com) trừ khi origin B cho phép rõ ràng. "Origin" được tính bằng 3 yếu tố: protocol + domain + port — chỉ cần khác 1 trong 3 là khác origin (kể cả http:// vs https:// cùng domain, hay :3000 vs :8080).
Đây là cơ chế bảo vệ người dùng: nếu không có same-origin policy, 1 trang web độc hại bất kỳ có thể âm thầm gọi API ngân hàng bạn đang đăng nhập và đọc được dữ liệu trả về. CORS là cơ chế để server chủ động nới lỏng giới hạn này cho những origin nó tin tưởng.
Cách hoạt động
Server trả về các header cho biết origin nào được phép gọi:
| Header | Ý nghĩa |
|---|---|
Access-Control-Allow-Origin | Origin nào được phép đọc response (* = cho phép tất cả, hoặc 1 domain cụ thể) |
Access-Control-Allow-Methods | HTTP method nào được phép (GET, POST, PUT...) |
Access-Control-Allow-Headers | Header nào client được phép gửi kèm |
Access-Control-Allow-Credentials | Có cho phép gửi kèm cookie/credential cross-origin không |
Preflight request — request "dò đường" trước
Với các request "không đơn giản" (ví dụ dùng method PUT/DELETE, hoặc có header tuỳ chỉnh như Authorization), trình duyệt tự động gửi trước 1 request OPTIONS (gọi là preflight) để hỏi server "tôi được phép gửi request thật không". Chỉ khi server trả lời đồng ý (đúng header CORS), trình duyệt mới gửi tiếp request thật. Đây là lý do đôi khi thấy 2 request cho 1 lần gọi API trong tab Network của DevTools.
Sai lầm thường gặp
- Dùng
Access-Control-Allow-Origin: *cho API có xác thực (cookie/session) —*không được phép dùng chung vớiAccess-Control-Allow-Credentials: true(browser sẽ tự chặn), và kể cả khi kỹ thuật cho phép được thì đây vẫn là cấu hình quá lỏng lẻo, mở API cho mọi origin trên internet gọi được. - Nhầm CORS là cơ chế bảo mật API — CORS chỉ bảo vệ trình duyệt của người dùng, không bảo vệ được server. Ai đó gọi thẳng API qua curl/Postman/backend khác thì CORS không chặn được gì cả (không có "trình duyệt" nào để áp policy). Muốn bảo vệ API thực sự vẫn phải dựa vào authentication/authorization.
- "Tắt CORS" ở phía client để hết lỗi — lỗi CORS chỉ sửa được ở phía server (server phải trả đúng header cho phép), sửa ở phía client (tắt security của trình duyệt, dùng proxy che mắt lúc dev) chỉ là né tạm trong lúc phát triển, không phải giải pháp cho production.