Tìm hiểu lý do cần phải tách biệt nhiều nguồn gốc để sử dụng các tính năng mạnh mẽ như SharedArrayBuffer
, performance.measureUserAgentSpecificMemory()
và bộ hẹn giờ có độ phân giải cao với độ chính xác cao hơn.
Giới thiệu
Trong bài viết Tạo trang web "được phân tách nhiều nguồn gốc" bằng COOP và COEP, chúng tôi đã giải thích cách áp dụng trạng thái "được phân tách nhiều nguồn gốc" bằng COOP và COEP. Đây là bài viết đồng hành giải thích lý do cần phải tách biệt nhiều nguồn gốc để bật các tính năng mạnh mẽ trên trình duyệt.
Thông tin khái quát
Web được xây dựng dựa trên chính sách cùng nguồn gốc: một tính năng bảo mật hạn chế cách tài liệu và tập lệnh có thể tương tác với tài nguyên từ một nguồn gốc khác. Nguyên tắc này hạn chế các cách mà trang web có thể truy cập vào tài nguyên trên nhiều nguồn gốc. Ví dụ: một tài liệu từ https://a.example
bị ngăn truy cập vào dữ liệu được lưu trữ tại https://b.example
.
Tuy nhiên, chính sách cùng nguồn gốc đã có một số ngoại lệ trước đây. Mọi trang web đều có thể:
- Nhúng iframe trên nhiều nguồn gốc
- Bao gồm các tài nguyên trên nhiều nguồn gốc như hình ảnh hoặc tập lệnh
- Mở cửa sổ bật lên trên nhiều nguồn gốc bằng tệp tham chiếu DOM
Nếu có thể thiết kế web từ đầu, thì các ngoại lệ này sẽ không tồn tại. Rất tiếc, vào thời điểm cộng đồng web nhận ra các lợi ích chính của chính sách nghiêm ngặt về cùng nguồn gốc, web đã dựa vào các trường hợp ngoại lệ này.
Các hiệu ứng phụ bảo mật của chính sách cùng nguồn gốc lỏng lẻo như vậy đã được vá theo hai cách. Một cách là thông qua việc giới thiệu một giao thức mới có tên là Chia sẻ tài nguyên trên nhiều nguồn gốc (CORS). Mục đích của giao thức này là đảm bảo rằng máy chủ cho phép chia sẻ tài nguyên với một nguồn gốc nhất định. Một cách khác là xoá ngầm quyền truy cập trực tiếp của tập lệnh vào tài nguyên trên nhiều nguồn gốc trong khi vẫn duy trì khả năng tương thích ngược. Những tài nguyên trên nhiều nguồn gốc như vậy được gọi là tài nguyên "mờ". Ví dụ: đây là lý do tại sao việc thao tác các pixel của hình ảnh nhiều nguồn gốc thông qua CanvasRenderingContext2D
sẽ không thành công trừ khi bạn áp dụng CORS cho hình ảnh đó.
Tất cả các quyết định liên quan đến chính sách này đều diễn ra trong một nhóm ngữ cảnh duyệt web.
Trong một thời gian dài, việc kết hợp CORS và tài nguyên mờ là đủ để đảm bảo an toàn cho trình duyệt. Đôi khi, các trường hợp hiếm gặp (chẳng hạn như lỗ hổng JSON) được phát hiện và cần được vá, nhưng nhìn chung, nguyên tắc không cho phép quyền đọc trực tiếp vào các byte thô của tài nguyên trên nhiều nguồn gốc đã thành công.
Tất cả điều này đã thay đổi với Spectre, giúp mọi dữ liệu được tải vào cùng một nhóm ngữ cảnh duyệt web với mã của bạn có thể đọc được. Bằng cách đo lường thời gian thực hiện một số thao tác nhất định, kẻ tấn công có thể đoán được nội dung của bộ nhớ đệm CPU và thông qua đó, nội dung của bộ nhớ của quy trình. Các cuộc tấn công theo thời gian như vậy có thể xảy ra với bộ hẹn giờ có độ chi tiết thấp tồn tại trong nền tảng, nhưng có thể được tăng tốc bằng bộ hẹn giờ có độ chi tiết cao, cả rõ ràng (như performance.now()
) và ngầm ẩn (như SharedArrayBuffer
). Nếu evil.com
nhúng một hình ảnh trên nhiều nguồn gốc, thì kẻ tấn công có thể sử dụng một cuộc tấn công Spectre để đọc dữ liệu pixel của hình ảnh đó, khiến các biện pháp bảo vệ dựa trên "mức độ mờ" trở nên không hiệu quả.
Lý tưởng nhất là tất cả các yêu cầu trên nhiều nguồn gốc phải được máy chủ sở hữu tài nguyên kiểm tra rõ ràng. Nếu máy chủ sở hữu tài nguyên không cung cấp quy trình kiểm tra, thì dữ liệu sẽ không bao giờ lọt vào nhóm ngữ cảnh duyệt web của một tác nhân độc hại, do đó sẽ nằm ngoài tầm tấn công của mọi cuộc tấn công Spectre mà trang web có thể thực hiện. Chúng tôi gọi đó là trạng thái tách biệt nhiều nguồn gốc. Đây chính là nội dung của COOP+COEP.
Ở trạng thái tách biệt nhiều nguồn gốc, trang web yêu cầu được coi là ít nguy hiểm hơn và điều này mở ra các tính năng mạnh mẽ như SharedArrayBuffer
, performance.measureUserAgentSpecificMemory()
và trình hẹn giờ có độ phân giải cao với độ chính xác cao hơn. Nếu không, các tính năng này có thể được dùng cho các cuộc tấn công tương tự như Spectre. Điều này cũng ngăn việc sửa đổi document.domain
.
Chính sách đối với trình nhúng trên nhiều nguồn gốc
Chính sách đối với trình nhúng trên nhiều nguồn gốc (COEP) ngăn tài liệu tải bất kỳ tài nguyên nào trên nhiều nguồn gốc không cấp quyền rõ ràng cho tài liệu (bằng CORP hoặc CORS). Với tính năng này, bạn có thể khai báo rằng một tài liệu không thể tải các tài nguyên như vậy.
Để kích hoạt chính sách này, hãy thêm tiêu đề HTTP sau vào tài liệu:
Cross-Origin-Embedder-Policy: require-corp
COEP nhận một giá trị duy nhất là require-corp
. Điều này thực thi chính sách rằng tài liệu chỉ có thể tải tài nguyên từ cùng một nguồn gốc hoặc tài nguyên được đánh dấu rõ ràng là có thể tải từ một nguồn gốc khác.
Để có thể tải tài nguyên từ một nguồn gốc khác, tài nguyên đó cần hỗ trợ tính năng Chia sẻ tài nguyên trên nhiều nguồn gốc (CORS) hoặc Chính sách về tài nguyên trên nhiều nguồn gốc (CORP).
Chia sẻ tài nguyên trên nhiều nguồn gốc
Nếu một tài nguyên trên nhiều nguồn gốc hỗ trợ tính năng Chia sẻ tài nguyên trên nhiều nguồn gốc (CORS), thì bạn có thể sử dụng thuộc tính crossorigin
để tải tài nguyên đó vào trang web mà không bị COEP chặn.
<img src="https://third-party.example.com/image.jpg" crossorigin>
Ví dụ: nếu tài nguyên hình ảnh này được phân phát bằng tiêu đề CORS, hãy sử dụng thuộc tính crossorigin
để yêu cầu tìm nạp tài nguyên sẽ sử dụng chế độ CORS. Điều này cũng ngăn hình ảnh tải trừ phi hình ảnh đó đặt tiêu đề CORS.
Tương tự, bạn có thể tìm nạp dữ liệu trên nhiều nguồn gốc thông qua phương thức fetch()
. Phương thức này không yêu cầu xử lý đặc biệt, miễn là máy chủ phản hồi bằng các tiêu đề HTTP phù hợp.
Chính sách về tài nguyên trên nhiều nguồn gốc
Chính sách tài nguyên trên nhiều nguồn gốc (CORP) ban đầu được giới thiệu dưới dạng một lựa chọn để bảo vệ tài nguyên của bạn khỏi bị tải bởi một nguồn gốc khác. Trong ngữ cảnh của COEP, CORP có thể chỉ định chính sách của chủ sở hữu tài nguyên về những người có thể tải tài nguyên.
Tiêu đề Cross-Origin-Resource-Policy
có thể có ba giá trị:
Cross-Origin-Resource-Policy: same-site
Bạn chỉ có thể tải các tài nguyên được đánh dấu là same-site
từ cùng một trang web.
Cross-Origin-Resource-Policy: same-origin
Bạn chỉ có thể tải các tài nguyên được đánh dấu là same-origin
từ cùng một nguồn gốc.
Cross-Origin-Resource-Policy: cross-origin
Mọi trang web đều có thể tải các tài nguyên được đánh dấu là cross-origin
. (Giá trị này đã được thêm vào thông số kỹ thuật CORP cùng với COEP.)
Chính sách về trình mở trên nhiều nguồn gốc
Chính sách trình mở trên nhiều nguồn gốc (COOP) cho phép bạn đảm bảo rằng cửa sổ cấp cao nhất được tách biệt với các tài liệu khác bằng cách đặt các tài liệu đó vào một nhóm ngữ cảnh duyệt web khác để các tài liệu đó không thể tương tác trực tiếp với cửa sổ cấp cao nhất. Ví dụ: nếu một tài liệu có COOP mở một cửa sổ bật lên, thì thuộc tính window.opener
của tài liệu đó sẽ là null
. Ngoài ra, thuộc tính .closed
của tham chiếu của trình mở đến thuộc tính đó sẽ trả về true
.
Tiêu đề Cross-Origin-Opener-Policy
có thể có ba giá trị:
Cross-Origin-Opener-Policy: same-origin
Các tài liệu được đánh dấu là same-origin
có thể chia sẻ cùng một nhóm ngữ cảnh duyệt web với các tài liệu cùng nguồn gốc cũng được đánh dấu rõ ràng là same-origin
.
Cross-Origin-Opener-Policy: same-origin-allow-popups
Tài liệu cấp cao nhất có same-origin-allow-popups
giữ lại các tệp tham chiếu đến bất kỳ cửa sổ bật lên nào không đặt COOP hoặc chọn không tách biệt bằng cách đặt COOP là unsafe-none
.
Cross-Origin-Opener-Policy: unsafe-none
unsafe-none
là giá trị mặc định và cho phép thêm tài liệu vào nhóm ngữ cảnh duyệt web của trình mở, trừ phi chính trình mở có COOP là same-origin
.
Tóm tắt
Nếu bạn muốn đảm bảo quyền truy cập vào các tính năng mạnh mẽ như SharedArrayBuffer
, performance.measureUserAgentSpecificMemory()
hoặc trình hẹn giờ có độ phân giải cao với độ chính xác cao hơn, bạn chỉ cần nhớ rằng tài liệu của mình cần sử dụng cả COEP với giá trị require-corp
và COOP với giá trị same-origin
. Nếu không có một trong hai, trình duyệt sẽ không đảm bảo đủ khả năng tách biệt để bật các tính năng mạnh mẽ đó một cách an toàn. Bạn có thể xác định tình trạng của trang bằng cách kiểm tra xem self.crossOriginIsolated
có trả về true
hay không.
Tìm hiểu các bước triển khai việc này trong bài viết Tạo trang web "được phân tách giữa các nguồn gốc" bằng cách sử dụng COOP và COEP.