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 chặn các mục đích 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 một phần tử <canvas>. Đây có thể là những tài nguyên công khai mà bất kỳ ai cũng 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, các nhà phát triển thường dùng những giải pháp tạm thời như JSONP.

Cơ chế 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ủ cho trình duyệt biết rằng máy chủ có thể sử dụng một nguồn 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
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 cách sử dụ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 để nhận được một tài nguyên.

Tiêu đề HTTP thương lượng 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 một tiêu đề và một 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 thể hiện dưới dạng cặp khoá-giá trị. Tiêu đề của yêu cầu và tiêu đề phản hồi chứa thông tin khác nhau.

Tiêu đề của 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 chiếc bánh quy 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 nội dung "Dữ liệu trong phản hồi này được mã hoá bằng gzip. Đừng lưu nội dung này vào bộ nhớ đệm".

Nội dung

Chính tin nhắn đó. Đây 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 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ửi yêu cầu có thể truy cập vào tài nguyên của máy chủ đó. 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 của ứng dụng (trình duyệt)

Khi trình duyệt thực hiện một yêu cầu trên nhiều nguồn gốc, trình duyệt sẽ thêm một tiêu đề Origin có 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, trong đó 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 đăng nhập 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 lựa chọn tìm nạp như trong ví dụ sau. Điều này bao gồm cả cookie trong yêu cầu như sau:

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

Phản hồi

Access-Control-Allow-Origin phải được đặt thành một nguồn gốc cụ thể (không có ký tự đại diện bằng cách sử dụng *) và Access-Control-Allow-Credentials phải được đặt 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 đưa ra yêu cầu HTTP phức tạp, trình duyệt sẽ thêm một yêu cầu kiểm tra trước 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.
  • Một yêu cầu bao gồm các tiêu đề khác ngoài Accept, Accept-Language hoặc Content-Language.
  • Một 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 sẽ tự động tạo mọi yêu cầu kiểm tra trước cần thiết và gửi chúng trước thông báo yêu cầu thực tế. Yêu cầu kiểm tra 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 kiểm tra trước 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 kiểm tra trước.