Chia sẻ tài nguyên trên nhiều nguồn gốc (CORS)

Chia sẻ tài nguyên trên nhiều nguồn gốc một cách an toàn

Mariko Kosaka

Chính sách cùng nguồn gốc của trình duyệt chặn việc đọc tài nguyên từ một nguồn gốc khác. Cơ chế này ngăn các trang web độc hại đọc dữ liệu của các trang web khác, nhưng cũng ngăn việc sử dụng hợp pháp.

Các ứng dụng web hiện đại thường muốn lấy tài nguyên từ một nguồn gốc khác, ví dụ: truy xuất dữ liệu JSON từ một miền khác hoặc tải hình ảnh từ một trang web khác vào phần tử <canvas>. Đây có thể là các tài nguyên công khai mà mọi người đều có thể đọc, nhưng chính sách cùng nguồn gốc sẽ chặn việc sử dụng các tài nguyên này. Trước đây, nhà phát triển đã sử dụng các giải pháp như JSONP.

Chia sẻ tài nguyên trên nhiều nguồn gốc (CORS) khắc phục vấn đề này theo cách chuẩn hoá. Việc bật CORS cho phép máy chủ thông báo cho trình duyệt rằng máy chủ có thể sử dụng một nguồn gốc bổ sung.

Yêu cầu tài nguyên hoạt động như thế nào trên web?

yêu cầu và phản hồi
Hình minh hoạ yêu cầu của ứng dụng và phản hồi của máy chủ.

Trình duyệt và máy chủ có thể trao đổi dữ liệu qua mạng bằng Giao thức truyền siêu văn bản (HTTP). HTTP xác định các quy tắc giao tiếp giữa bên yêu cầu và bên phản hồi, bao gồm cả thông tin cần thiết để lấy tài nguyên.

Tiêu đề HTTP đàm phán việc trao đổi thông báo giữa ứng dụng và máy chủ, đồng thời được dùng để xác định quyền truy cập. Cả yêu cầu của trình duyệt và thông báo phản hồi của máy chủ đều được chia thành tiêu đềnội dung.

Thông tin về thông báo, chẳng hạn như loại thông báo hoặc cách mã hoá thông báo. Tiêu đề có thể bao gồm nhiều thông tin được biểu thị dưới dạng cặp khoá-giá trị. Tiêu đề yêu cầu và tiêu đề phản hồi chứa thông tin khác nhau.

Tiêu đề yêu cầu mẫu

Accept: text/html
Cookie: Version=1

Tiêu đề này tương đương với việc nói "Tôi muốn nhận HTML trong phản hồi. Đây là một cookie mà tôi có."

Tiêu đề phản hồi mẫu

Content-Encoding: gzip
Cache-Control: no-store

Tiêu đề này tương đương với việc nói rằng "Dữ liệu trong phản hồi này được mã hoá bằng gzip. Không lưu nội dung này vào bộ nhớ đệm."

Nội dung

Chính thông báo đó. Đó có thể là văn bản thuần tuý, tệp nhị phân hình ảnh, JSON, HTML hoặc nhiều định dạng khác.

CORS hoạt động như thế nào?

Chính sách cùng nguồn gốc yêu cầu trình duyệt chặn các yêu cầu trên nhiều nguồn gốc. Khi bạn cần một tài nguyên công khai từ một nguồn gốc khác, máy chủ cung cấp tài nguyên sẽ cho trình duyệt biết rằng nguồn gốc gửi yêu cầu có thể truy cập vào tài nguyên của nó. Trình duyệt sẽ ghi nhớ điều đó và cho phép chia sẻ tài nguyên trên nhiều nguồn gốc cho tài nguyên đó.

Bước 1: yêu cầu ứng dụng (trình duyệt)

Khi thực hiện yêu cầu nhiều nguồn gốc, trình duyệt sẽ thêm tiêu đề Origin với nguồn gốc hiện tại (lược đồ, máy chủ và cổng).

Bước 2: phản hồi của máy chủ

Khi thấy tiêu đề này và muốn cho phép truy cập, máy chủ sẽ thêm tiêu đề Access-Control-Allow-Origin vào phản hồi chỉ định nguồn gốc yêu cầu (hoặc * để cho phép mọi nguồn gốc).

Bước 3: trình duyệt nhận được phản hồi

Khi trình duyệt thấy phản hồi này có tiêu đề Access-Control-Allow-Origin thích hợp, trình duyệt sẽ chia sẻ dữ liệu phản hồi với trang web của ứng dụng.

Chia sẻ thông tin xác thực với CORS

Vì lý do bảo mật, CORS thường được dùng cho các yêu cầu ẩn danh, trong đó người yêu cầu không được xác định. Nếu muốn gửi cookie khi sử dụng CORS (có thể xác định người gửi), bạn cần thêm các tiêu đề bổ sung vào yêu cầu và phản hồi.

Yêu cầu

Thêm credentials: 'include' vào các tuỳ chọn tìm nạp như trong ví dụ sau. Cookie này bao gồm yêu cầu như sau:

fetch('https://example.com', {
  mode
: 'cors',
  credentials
: 'include'
})

Phản hồi

Bạn phải đặt Access-Control-Allow-Origin thành một nguồn gốc cụ thể (không có ký tự đại diện bằng *) và đặt Access-Control-Allow-Credentials thành true.

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Credentials: true

Yêu cầu kiểm tra trước cho các lệnh gọi HTTP phức tạp

Khi một ứng dụng web thực hiện một yêu cầu HTTP phức tạp, trình duyệt sẽ thêm một yêu cầu trước khi bay vào đầu chuỗi yêu cầu.

Quy cách CORS xác định yêu cầu phức tạp như sau:

  • Yêu cầu sử dụng các phương thức khác ngoài GET, POST hoặc HEAD.
  • Yêu cầu có chứa các tiêu đề khác ngoài Accept, Accept-Language hoặc Content-Language.
  • Yêu cầu có tiêu đề Content-Type khác với application/x-www-form-urlencoded, multipart/form-data hoặc text/plain.

Trình duyệt tự động tạo mọi yêu cầu cần thiết trước khi bay và gửi các yêu cầu đó trước khi gửi thông báo yêu cầu thực tế. Yêu cầu trước chuyến bay là một yêu cầu OPTIONS như ví dụ sau:

OPTIONS /data HTTP/1.1
Origin: https://example.com
Access-Control-Request-Method: DELETE

Ở phía máy chủ, ứng dụng nhận được yêu cầu sẽ phản hồi yêu cầu trước khi khởi chạy bằng thông tin về các phương thức mà ứng dụng chấp nhận từ nguồn gốc này:

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://example.com
Access-Control-Allow-Methods: GET, DELETE, HEAD, OPTIONS

Phản hồi của máy chủ cũng có thể bao gồm tiêu đề Access-Control-Max-Age để chỉ định thời lượng tính bằng giây để lưu kết quả kiểm tra trước vào bộ nhớ đệm. Điều này cho phép ứng dụng gửi nhiều yêu cầu phức tạp mà không cần lặp lại yêu cầu trước khi bay.