1. Giới thiệu
Trong thời đại ngày nay, các website không chỉ đơn thuần là kết nối từ phía Front-End đến phía Server mà còn phải liên kết đến nhiều bên thứ ba. Việc càng nhiều nguồn có thể truy cập vào hệ thống của bạn sẽ làm tăng nguy cơ hệ thống bị tấn công. Có rất nhiều cách bảo mật hệ thống được sinh ra từ cả phía Front-End và cả Server, các trình duyệt (Browser) cũng không chịu thụt lùi mà cũng có những cách bảo vệ riêng, trong đó có CORS
2. CORS là gì?
CORS (Cross-Origin Resource Sharing) là một tiêu chuẩn của trình duyệt (Browser) nhằm bảo vệ các tài nguyên web không bị truy cập trái phép bởi các miền không thuộc phạm vi cho phép
Nhờ CORS, các trình duyệt sẽ ngăn chặn các trang web có một Origin
không hợp lệ truy cập vào máy chủ.
*Xem thêm về Origin ở #4
3. Tại sao CORS lại quan trọng?
Bảo vệ dữ liệu: CORS ngăn chặn các cuộc tấn công XSS (Cross-Site Scripting) và CSRF (Cross-Site Request Forgery) giúp bảo vệ các dữ liệu quan trọng.
Tăng cường bảo mật: CORS sinh ra để chắc chắn rằng chỉ những yêu cầu hợp lệ mới được phép truy cập vào dữ liệu.
Tích hợp API: Nếu không có CORS, các ứng dụng hiện đại sử dụng REST API hoặc GraphQL sẽ gặp khó khăn trong việc trao đổi dữ liệu giữa client và server, đặc biệt trong các hệ thống phân tán.
*xem thêm về tích hợp API ở #4
4. Origin và tầm quan trọng của CORS trong việc tích hợp API
4.1. Origin
Origin gồm có 3 thành phần:
- Scheme (giao thức), ví dụ: HTTP, HTTPS
- Hostname (tên miền), ví dụ: nccizthebezt.com
- Port (cổng), ví dụ: 80, 3000, 8000
Một Origin hoàn chỉnh: http://nccizthebezt.com: 8000
https://nccizthebezt.com: 3000
Origin được coi là giống nhau (hay hợp lệ) khi và chỉ khi chúng có cùng Scheme
, Hostname
, Port
. Nếu không, chúng sẽ được coi là khác Origin (Cross-Origin)
Ví dụ:
http://nccizthebezt.com:8000
https://nccizthebezt.com:8000
https://nccizthebezt.com:3000
http://nccizthebezt.com:3000
http://nccizthebezt.com:8000
http://nccizthebezt.com:3000
Ví dụ 1 là chung Origin vì chúng có cùng Scheme, Hostname, Port
Ví dụ 2 và 3 là khác Origin vì chúng lần lượt khác Scheme và Port
4.2. Tầm quan trọng của CORS trong việc tích hợp API
Nếu server không bật CORS, trình duyệt sẽ từ chối các yêu cầu từ một origin khác, ngay cả khi đó là những yêu cầu hợp lệ. Điều này dẫn đến:
- Ứng dụng không hoạt động như mong muốn: Client không thể lấy dữ liệu từ API server để hiển thị hoặc gửi dữ liệu để xử lý.
- Người dùng gặp lỗi: Trình duyệt xảy ra lỗi CORS
Ví dụ:
- Không có CORS:
- Client gửi một yêu cầu
GET
đếnhttps://api.example.com/users
. - Trình duyệt kiểm tra thấy origin của client: (
https://frontend.example.com
) khác origin của server (https://api.example.com
). - Do server không bật CORS, trình duyệt chặn yêu cầu này, không gửi đến server.
- Client gửi một yêu cầu
- Có CORS:
- Server bật CORS và thêm header phản hồi:
Access-Control-Allow-Origin: https://frontend.example.com
- Trình duyệt cho phép yêu cầu tiếp tục và trả về kết quả từ server.
- Server bật CORS và thêm header phản hồi:
5. Cách cấu hình CORS đơn giản bằng Spring Boot và ExpressJS
5.1. Cấu hình CORS bằng Spring Boot
- Spring Boot
@CrossOrigin
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
// Cho phép tất cả các miền truy cập vào endpoint này
@CrossOrigin(origins = "*")
@GetMapping("/api/data")
public String getData() {
return "Hello from Spring Boot";
}
// Chỉ cho phép miền https://example.com truy cập vào endpoint này
@CrossOrigin(origins = "https://example.com")
@GetMapping("/api/secure-data")
public String getSecureData() {
return "Secure data";
}
}
- Spring Boot
WebMvcConfigurer
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**") // Đường dẫn API được áp dụng CORS
.allowedOrigins("https://example.com", "https://anotherdomain.com") // Các origin được phép
.allowedMethods("GET", "POST", "PUT", "DELETE") // Các phương thức HTTP được phép
.allowedHeaders("Content-Type", "Authorization") // Các header được phép
.allowCredentials(true) // Cho phép gửi cookies
.maxAge(3600); // Thời gian cache preflight request là 1 giờ
}
};
}
}
5.2. Cấu hình CORS bằng ExpressJS
- Cài đặt thư viện
npm install cors
- Sử dụng
const express = require('express');
const cors = require('cors');
const app = express();
// Cấu hình CORS cho tất cả các miền
app.use(cors());
// Hoặc chỉ cho phép một số miền cụ thể
app.use(cors({
origin: ['https://example.com', 'https://anotherdomain.com'], // Các origin được phép
methods: ['GET', 'POST', 'PUT', 'DELETE'], // Các phương thức HTTP được phép
allowedHeaders: ['Content-Type', 'Authorization'], // Các header được phép
credentials: true, // Cho phép gửi cookies
maxAge: 3600 // Thời gian cache preflight request là 1 giờ
}));
// Ví dụ một API trong Express
app.get('/api/data', (req, res) => {
res.json({ message: 'Hello from ExpressJS' });
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
6. Các lỗi thường gặp
No ‘Access-Control-Allow-Origin’ header is present on the requested resource
- Nguyên nhân: Máy chủ chưa cấu hình hoặc không trả về header
Access-Control-Allow-Origin
. - Giải pháp: Đảm bảo máy chủ thêm header này trong phản hồi.
CORS policy: Response to preflight request doesn’t pass access control check
- Nguyên nhân: Yêu cầu kiểm tra trước (OPTIONS) không được xử lý đúng.
- Giải pháp: Đảm bảo máy chủ cho phép phương thức OPTIONS và trả về các header CORS.
The value of the ‘Access-Control-Allow-Origin’ header must not be the wildcard ‘*’
- Nguyên nhân: Không được sử dụng ký tự
*
khi yêu cầu bao gồm thông tin xác thực (credentials). - Giải pháp: Chỉ định cụ thể origin được phép.
Lưu ý: các lập trình viên có thể thiết lập CORS cho phép tất cả mọi nguồn truy cập vào hệ thống bằng dùng * trong phần config, đều này không được khuyến khích vì nó tiềm ẩn rủi ro hệ thống dễ bị tấn công hơn
7. Kết luận
CORS là một phần không thể thiếu trong việc xây dựng các ứng dụng web hiện đại. Bằng cách hiểu rõ và cấu hình CORS một cách đúng đắn, bạn có thể đảm bảo ứng dụng của mình hoạt động mượt mà, đồng thời bảo vệ người dùng trước các mối đe dọa bảo mật.
Nếu bạn muốn tìm hiểu thêm về CORS, có thể đọc thêm tại: Cross-Origin Resource Sharing (CORS) – HTTP | MDN