CORS là gì?

Dùng CORS làm gì cho phức tạp?

Cái gì cũng có nguyên nhân của nó cả, đầu tiên phải kể đến same origin policy, đây là một trong những chính sách an ninh quan trọng nhất trên các trình duyệt hiện đại được đưa ra bơi Netscape vào năm 1995. Về cơ bản thì đây là một chính sách quy định nội dung của một domain chỉ được đọc và thay đổi bới một thành phần khác cũng nằm cùng domain đó, các yêu cầu từ các domain khác sẽ bị chặn lại.

Giả sử nếu không có same origin policy, vào một ngày đẹp trời bạn mở trình duyệt vào Facebook đồng thời ở một tab khác bạn đang truy cập một trang web chứa mã độc và script được đặt sẵn trên trang này có thể tạo request lên server của Facebook từ đó có thể lấy được thông tin, truy cập được một vài tính năng cơ bản với source của tab Facebook. Vì lý do này, trình duyệt phải có cơ chế phân biệt được request của nguồn nào thì được phép truy cập vào nguồn nào từ đó tránh được các cuộc tấn công giả mạo ngoài ý muốn.

Mặc dù SOP có hiệu quả trong việc ngăn chặn việc truy cập trái phép từ các domain khác nhau nhưng đồng thời nó cũng ngăn cản những tương tác hợp lệ giữa các server hoặc client đáng tin cậy. Ví dụ như api.example.comimage.example.com, hai domain này chắc chắn là không cùng origin rồi.

CORS (Cross Origin Resource Sharing) là một tính năng mới được tích hợp trong HTML5, thêm vào các HTTP headers chỉ dẫn cho trình duyệt web về sử dụng và quản lý nội dung cross-domain, cho phép lấy dữ liệu từ một trang khác thông qua XMLHttpRequest.

CORS hoạt động ra sao?

Khi trình duyệt gửi một request đến một domain khác để yêu cầu làm một việc gì đó, những request này sẽ được gắn thêm một header có tên là origin để xác định origin của client, giá trị này được thêm tự động bởi trình duyệt và không ai có thể thay đổi nó được. Header này đại diện cho nguồn gốc truy vấn.

Orgin được cấu tạo dựa trên ba phần:

  • Protocol/Scheme: (Http/Https)
  • Host: server/domain
  • Port: cổng, nếu giá trị này là giá trị mặc định 80 thì không cần

Server sẽ xem xét xem origin trong request người dùng gửi có hợp lệ hay không, nếu là hợp lệ thì sẽ trả về response kèm với header Access-Controll-Allow-Origin. Header này sẽ cho biết xem client có phải là hợp lệ hay không rồi từ đó trình duyệt mới tiếp tục thực hiện quá trình request. Access-Control-Allow-Origin liệt kê các tên miền được phép thực hiện yêu cầu của CORS. Ký tự * cho phép tất cả các domain khác thực hiện yêu cầu. Tuy nhiên cách này thường được coi là không an toàn ngoại trừ trường hợp API của bạn được sử dụng với mục đích công khai và ai cũng có quyền được phép truy cập.

Ví dụ một reequest từ trang https://foo.example:

GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example

Response

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml

[…XML Data…]

Nếu không có header Access-Control-Allow-Origin hoặc giá trị của nó không hợp lệ thì trình duyệt sẽ thông báo lỗi.

Các header liên quan đến CORS đều có phần tiền tố bắt đầu bằng Access-Controll. Ngoài Access-Controll-Allow-Origin, header liên quan đến CORS có thể chứa:

  • Access-Control-Allow-Methods: danh sách các phương thức HTTP mà server cho phép client sử dụng (GET, POST, PUT, DELETE...), không thể được ghi đè hay sửa đổi.
  • Access-Control-Allow_Headers: chứa danh sách những header mà phía server hiện đang hỗ trợ (x-authentication-token, ...), nếu trong request phía client gửi không chứa những header không nằm trong danh sách này sẽ bị server bỏ qua.
  • Access-Control-Max-Age: Mô tả thời gian hợp lệ của preflight request, nếu quá hạn, trình duyệt sẽ tạo môt pre-flight request mới.

Các truy vấn dùng CORS

Theo chuẩn quốc tế, các truy vấn sau sẽ phải dùng CORS:

  • Các truy vấn bằng XMLHttpRequest hoặc Fetch API đến một domain khác.
  • Ảnh, video được vẽ vào canvas sử dụng drawImage.
  • Web fonts truy vấn đến domain khác qua fontface trong CSS, trong đó trang web chỉ có thể sử dụng font dạng True Type nếu được cho phép.
  • WebGL Texture

Pre-flight requests

Pre-flight request là một loại CORS request, được gửi khi có những request tác động đến database như POST, PUT, DELETE,... Đầu tiên, trình duyệt sẽ gửi một request với phương thức OPTION tới resource của domain trước khi gửi request chính nhằm để thăm dò xem request chính có được phía server hỗ trợ hoặc request này có hợp lệ hay không. Ngoài ra trong trường hợp bạn thêm những custom header vào trong request thì việc gửi một pre-flight request trước cũng là cần thiết.

Ví dụ ở trình duyệt chúng ta truy cập vào trang https://www.alice.com và gửi một request đến POST: https://www.api.alice.com/users. Đầu tiên trình duyêt sẽ gửi đi pre-flight request (OPTION) đến bên phía server với request method và request header giả định của request chính trong đó các header Access-Control-Request-MethodAccess-Control-Request-Headers sẽ được trình duyêt tự động thêm vào.

OPTIONS /users/ HTTP/1.1
Host: api.alice.com
Origin: https://www.alice.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Authorization, Content-Type
[Rest of request...]

Server sẽ gửi về reponse chứa thông tin các HTTP methods và headers được cho phép.

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://www.alice.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
Content-Type: application/json
[Rest of response...] 

Nếu request được cho phép, trình duyệt sẽ gửi đi CORS request (request chính), các bước sau cũng được thực hiện giống như vậy.

POST /users/ HTTP/1.1
Host: api.alice.com
Authorization: root
Content-Type: application/json
Origin: https://www.alice.com
[Rest of request...]

Reponse từ phía server chứa giá trị origin trong Access-Control-Allow-Origin , trình duyệt lúc này sẽ thực hiện xử lý và gửi các request tiếp theo.

Kết luận

Trên đây là những phần cơ bản về CORS mà mình có thể tìm hiểu được, hy vọng chúng sẽ giúp ích được cho các ban phần nào.

Nếu có thắc mắc hoặc góp ý cho bài viết thì các bạn để lại lời nhắn nho nhỏ ở phía phần comment để mình có thể giải đáp cũng như cải thiện bài viết được tốt hơn.

Cảm ơn bạn đã đọc đến cuối bài viết ❤️.

Tham khảo

https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS

https://codeaholicguy.com/2018/05/07/cors-la-gi/