0

Part 1: Đi về lịch sử của CORS để hiểu hơn về nó và các cách thiết lập CORS

Chào mọi người,

Mở bài

Chắc là mọi người đang setup CORS cho server mình hở ??? chắc là vậy rồi thì ae mình mới gặp nhau ở bài này.

Google đã dẫn anh em đến đây

Hẳn anh em đã gõ như thế này?

Google Search: How to fix cors in spring boot, How to fix cors in expressjs hoặc là: Cách fix lỗi cors trong ...,

Nếu anh em google search tiếng Việt thì sẽ vào đến đây, keke. Thôi ngồi nghỉ ăn miếng bánh, uống miếng nước đọc xong bài này rồi hãy fix lỗi cors nhé anh em. Để sau không phải đọc nó thêm lần nào nữa nhé 😆

Anh em đang gặp dòng chữ này ư, hmmmmm????

Access to fetch at 'http://<server_domain_api>/api/users' from origin 'https://<client_domain>.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No Access-Control-Allow-Origin header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

Hình ảnh như này thật quen thuộc làm sao image.png

Đoạn này dành cho anh em không đến từ Google search: Mình chắc chắn anh em kiểu gì cũng từng gặp lỗi trên hoặc các biến thể tương tự của nó ít nhất một lần. Còn không thì thôi sớm thôi, anh em sẽ gặp nó thôi, và có khi anh em quay lại đầu bài.


Thật là đớn đau làm sao, khi dev xong hết mọi thứ, testing đầy đủ các bước đúng công thức trong sách giáo khoa bằng Postman các kiểu, nhưng đến khi tích hợp APIs ở client thì cái gì đến nó cũng đến. Thôi vào bài viết nào.

Trở về quá khứ một xíu nha

1. Bối cảnh lịch sử

Trước khi khái niệm CORS (Cross-Origin Resource Sharing) ra đời, web được thiết kế để phục vụ các tài liệu tĩnh, và các trang web thường chỉ yêu cầu tài nguyên từ chính server mà chúng được lưu trữ. Khi các trang web bắt đầu trở nên phức tạp hơn, nhu cầu truy cập tài nguyên từ các nguồn khác (cross-origin) xuất hiện.

Tuy nhiên, các truy cập từ nguồn khác này mang theo nguy cơ bảo mật nghiêm trọng, đặc biệt khi trình duyệt thực hiện các yêu cầu mà không có cách để giới hạn hoặc kiểm soát chúng.

2. Same-Origin Policy (SOP)

Same-Origin Policy (Chính sách Cùng Nguồn) là nền tảng bảo mật đầu tiên cho các trình duyệt, xuất hiện từ cuối những năm 1990 (khoảng thời điểm trình duyệt Netscape 2.0).

Đây là một quy tắc bảo mật quan trọng được thiết kế để bảo vệ tài nguyên trên web khỏi các hành vi truy cập trái phép từ một domain khác.

Same-Origin Policy quy định rằng: Một tài nguyên (HTML, JavaScript, CSS, …) từ một origin (nguồn, bao gồm scheme, domainport) chỉ được phép truy cập các tài nguyên khác từ cùng một origin.

Note: scheme ở đây ý nói là http, https hoặc fpt,... Về mặt kỹ thuật thì không có protocol trong URL, chỉ có shchem mà thôi, cái đứng trước domain

Ví dụ: https://example.com GET / HTTP/1.1 Host: example.com. Thì https ở đây là scheme, còn HTTP/1.1 mới là protocol

Ví dụ:

Mục đích của SOP:

  • Ngăn chặn Cross-Site Scripting (XSS): Đảm bảo mã độc từ một trang khác không thể lấy dữ liệu nhạy cảm.
  • Ngăn chặn Cross-Site Request Forgery (CSRF): Không cho phép kẻ tấn công thực hiện yêu cầu bất hợp pháp thay mặt người dùng.

Hạn chế của SOP:

  • SOP quá hạn chế đối với các ứng dụng web hiện đại, nơi việc truy cập tài nguyên từ nhiều nguồn khác nhau là cần thiết (ví dụ: gọi API, tải tài nguyên từ CDN).

3. Nhu cầu giao tiếp giữa các origin

Với sự phát triển của web vào đầu những năm 2000, nhu cầu giao tiếp giữa các origin khác nhau trở nên phổ biến hơn:

Sự xuất hiện của AJAX (XMLHttpRequest):

AJAX xuất hiện vào năm 1999 (khi Microsoft giới thiệu ActiveX). Nó cho phép các trang web gửi yêu cầu đến server mà không cần tải lại trang. Tuy nhiên, SOP hạn chế AJAX chỉ có thể gửi yêu cầu đến cùng một origin.

Các ứng dụng web hiện đại cần:

  • Tải tài nguyên từ CDN (Content Delivery Network) để tăng hiệu năng (có thể là CSS, JS, hình ảnh…).
  • Gửi yêu cầu đến các API public từ server khác (ví dụ: Google Maps API, OpenWeather API…).
  • Kết nối với các microservices phân tán trên nhiều domain khác nhau.

Ví dụ về vấn đề:

  • Một ứng dụng web tại https://myapp.com muốn gửi yêu cầu đến https://api.myapp.com để lấy dữ liệu.
  • Với SOP, yêu cầu này sẽ bị chặn vì khác origin, mặc dù cả hai domain thuộc cùng một hệ thống.

4. Sự ra đời của CORS

Để giải quyết hạn chế của SOP, CORS (Cross-Origin Resource Sharing) ra đời vào năm 2005, do W3C (World Wide Web Consortium) đề xuất và phát triển.

Mục tiêu của CORS:

CORS mở rộng SOP, cho phép các server kiểm soát và cho phép các trình duyệt thực hiện yêu cầu từ các origin khác, trong khi vẫn đảm bảo bảo mật.

Cách CORS hoạt động:

  • Server quyết định tài nguyên của mình có thể được chia sẻ với các origin nào.
  • Trình duyệt gửi một yêu cầu Preflight Request để kiểm tra xem server có cho phép cross-origin hay không.
  • Nếu server cho phép, trình duyệt sẽ tiếp tục gửi yêu cầu chính (actual request).

Ưu điểm của CORS:

  • Vẫn giữ nguyên cơ chế bảo mật của SOP.
  • Linh hoạt hơn, cho phép server định nghĩa chính sách cụ thể về origin nào được truy cập tài nguyên.

5. Các mốc thời gian quan trọng

Đây là một số mốt thời gian anh em coi qua để biết chơi 😁

  • 1993: HTML <img> được giới thiệu, đánh dấu khái niệm subresource (tài nguyên phụ). Đây là thời điểm trình duyệt cần thực hiện cross-origin request để tải ảnh.
  • 1999: AJAX ra đời, dẫn đến sự bùng nổ của các ứng dụng web động, làm lộ rõ hạn chế của SOP.
  • 2005: W3C giới thiệu tiêu chuẩn CORS như một phần mở rộng của SOP.
  • 2009: Các trình duyệt chính thức hỗ trợ CORS (Firefox 3.5, Chrome 3, Safari 4).
  • Hiện tại: CORS là một tiêu chuẩn bảo mật cơ bản trong lập trình web.

CORS không phải thay thế SOP mà là một giải pháp mở rộng, đáp ứng nhu cầu phát triển của các ứng dụng web hiện đại. Nó cho phép các ứng dụng web linh hoạt hơn trong việc giao tiếp giữa các origin khác nhau, trong khi vẫn duy trì cơ chế bảo mật.

6. Ví dụ về chưa có CORS

Ví dụ quen thuộc về bank thôi, giờ không biết ví dụ về gì ngoài bank để cho nó có vẻ nguy hiểm nữa. Anh em nhìn hình demo sau nhé: image.png

Bối cảnh:

  • Bạn sử dụng một dịch vụ ngân hàng trực tuyến tại https://bank.com.
  • Sau khi đăng nhập, bạn thực hiện các thao tác như chuyển tiền, xem số dư tài khoản, v.v. Yêu cầu HTTP được gửi từ trình duyệt của bạn đến server của ngân hàng kèm theo cookie phiên đăng nhập (session cookie).
  • Server của ngân hàng sử dụng cookie này để xác thực bạn là người dùng đã đăng nhập.


Hacker khai thác

  • Hacker tạo một trang web độc hại tại https://evil.com
  • Hacker muốn thực hiện một hành vi Cross-Site Request Forgery (CSRF), tức là lợi dụng phiên đăng nhập của bạn ở https://bank.com để thực hiện các hành động mà bạn không hề hay biết (như chuyển tiền).


Cách hacker tấn công nếu CORS không tồn tại nè

  • Sau khi làm việc với ngân hàng xong, bạn vô tình nhấp vào một link hoặc quảng cáo dẫn đến trang web của hacker tại https://evil.com
  • Trong web của hacker có một đoạn javascript sau:
    fetch('https://bank.com/api/transfer', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify({
            accountTo: 'hacker_account',
            amount: 1000000
        })
    });
    


Điều gì xảy ra?

  • Trình duyệt của bạn sẽ thực hiện yêu cầu đến https://bank.com/api/transfer kèm theo cookie phiên đăng nhập của bạn với ngân hàng.
  • Server của ngân hàng nhận được yêu cầu này và xác định bạn đã đăng nhập hợp lệ (dựa vào cookie).
  • Kết quả: Hacker đã chuyển tiền từ tài khoản của bạn sang tài khoản của họ mà bạn không hề hay biết.


Rồi tại sao CORS chặn được tấn công có thể coi là đơn giản này?

  • Gửi một Preflight Request đến server ngân hàng để kiểm tra xem https://evil.com có được phép gửi yêu cầu hay không.
  • Server của ngân hàng phản hồi rằng nó không cho phép origin https://evil.com.
  • Trình duyệt sẽ chặn yêu cầu và hacker không thể thực hiện tấn công.


Nếu không có CORS, bất kỳ trang web nào bạn truy cập cũng có thể gửi yêu cầu đến các server khác mà bạn đã đăng nhập, lợi dụng cookie phiên đăng nhập để thực hiện các hành động trái phép. Đây chính là lý do tại sao CORS rất quan trọng trong việc bảo vệ các ứng dụng web hiện đại.


Thôi cũng bài cũng dài rồi, cưỡi ngựa xem hoa về CORS nhiêu đó thôi, chứ giờ mà viết thêm đọc đau đầu lắm, mình kết đây part 1 nhé anh em, hẹn anh em ở part 2 chúng ta sẽ tiến hành cài đặt CORS trong Java Spring Boot nha.

Cảm ơn mọi người đã đọc bài, hy vọng bài viết hữu ích với mọi người, Thanks!

Sài Gòn: 00:15, ngày 19/12/2024


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí