Tách biệt trang web cho nhà phát triển web

Chrome 67 trên máy tính có một tính năng mới có tên là Tách biệt trang web được bật theo mặc định. Bài viết này giải thích về tính năng Cách ly trang web, lý do cần thiết và lý do nhà phát triển web nên lưu ý đến tính năng này.

Tính năng Tách biệt trang web là gì?

Internet là nơi để xem video về mèo và quản lý ví tiền mã hoá, cùng nhiều thứ khác — nhưng bạn không muốn fluffycats.example có quyền truy cập vào những đồng tiền mã hoá quý giá của mình! May mắn thay, các trang web thường không thể truy cập vào dữ liệu của nhau trong trình duyệt nhờ Chính sách về cùng nguồn gốc. Tuy nhiên, các trang web độc hại có thể tìm cách bỏ qua chính sách này để tấn công các trang web khác và đôi khi, các lỗi bảo mật được tìm thấy trong mã trình duyệt thực thi Chính sách cùng nguồn gốc. Nhóm Chrome sẽ cố gắng khắc phục những lỗi như vậy nhanh nhất có thể.

Tính năng Tách biệt trang web là một tính năng bảo mật trong Chrome, cung cấp thêm một lớp phòng thủ để giảm khả năng thành công của các cuộc tấn công như vậy. Tính năng này đảm bảo rằng các trang từ các trang web khác nhau luôn được đưa vào các quy trình khác nhau, mỗi quy trình chạy trong một hộp cát giới hạn những việc mà quy trình được phép làm. Tính năng này cũng chặn quy trình nhận một số loại dữ liệu nhạy cảm nhất định từ các trang web khác. Do đó, với tính năng Cách ly trang web, một trang web độc hại sẽ khó sử dụng các cuộc tấn công kênh bên mang tính suy đoán như Spectre để đánh cắp dữ liệu từ các trang web khác. Khi nhóm Chrome hoàn tất các biện pháp thực thi bổ sung, tính năng Tách biệt trang web cũng sẽ giúp ích ngay cả khi trang của kẻ tấn công có thể vi phạm một số quy tắc trong quy trình của chính trang đó.

Tính năng Cách ly trang web giúp các trang web không đáng tin cậy khó truy cập hoặc đánh cắp thông tin từ tài khoản của bạn trên các trang web khác. Tính năng này tăng cường bảo vệ trước nhiều loại lỗi bảo mật, chẳng hạn như các cuộc tấn công kênh bên Meltdown và Spectre gần đây.

Để biết thêm thông tin chi tiết về tính năng Tách biệt trang web, hãy xem bài viết của chúng tôi trên blog Bảo mật của Google.

Chặn đọc trên nhiều nguồn gốc

Ngay cả khi tất cả các trang trên nhiều trang web được đưa vào các quy trình riêng biệt, các trang vẫn có thể yêu cầu một số tài nguyên phụ trên nhiều trang web một cách hợp lệ, chẳng hạn như hình ảnh và JavaScript. Một trang web độc hại có thể sử dụng phần tử <img> để tải tệp JSON chứa dữ liệu nhạy cảm, chẳng hạn như số dư tài khoản ngân hàng của bạn:

<img src="https://your-bank.example/balance.json" />
<!-- Note: the attacker refused to add an `alt` attribute, for extra evil points. -->

Nếu không có tính năng Cách ly trang web, nội dung của tệp JSON sẽ được đưa vào bộ nhớ của quy trình trình kết xuất. Tại thời điểm đó, trình kết xuất sẽ nhận thấy rằng đó không phải là định dạng hình ảnh hợp lệ và không hiển thị hình ảnh. Tuy nhiên, sau đó, kẻ tấn công có thể khai thác một lỗ hổng như Spectre để có thể đọc khối bộ nhớ đó.

Thay vì sử dụng <img>, kẻ tấn công cũng có thể sử dụng <script> để ghi dữ liệu nhạy cảm vào bộ nhớ:

<script src="https://your-bank.example/balance.json"></script>

Tính năng Chặn đọc trên nhiều nguồn gốc (CORB) là một tính năng bảo mật mới giúp ngăn nội dung của balance.json xâm nhập vào bộ nhớ của quy trình kết xuất dựa trên loại MIME của nội dung đó.

Hãy cùng tìm hiểu cách hoạt động của CORB. Một trang web có thể yêu cầu hai loại tài nguyên từ máy chủ:

  1. tài nguyên dữ liệu như tài liệu HTML, XML hoặc JSON
  2. tài nguyên đa phương tiện như hình ảnh, JavaScript, CSS hoặc phông chữ

Một trang web có thể nhận tài nguyên dữ liệu từ nguồn gốc của chính trang web đó hoặc từ các nguồn gốc khác bằng các tiêu đề CORS cho phép, chẳng hạn như Access-Control-Allow-Origin: *. Mặt khác, bạn có thể đưa tài nguyên phương tiện vào từ bất kỳ nguồn gốc nào, ngay cả khi không có tiêu đề CORS cho phép.

CORB ngăn quá trình kết xuất nhận tài nguyên dữ liệu trên nhiều nguồn gốc (tức là HTML, XML hoặc JSON) nếu:

  • tài nguyên có tiêu đề X-Content-Type-Options: nosniff
  • CORS không cho phép truy cập vào tài nguyên một cách rõ ràng

Nếu tài nguyên dữ liệu nhiều nguồn gốc không có tiêu đề X-Content-Type-Options: nosniff, thì CORB sẽ cố gắng đánh hơi phần nội dung phản hồi để xác định xem đó là HTML, XML hay JSON. Điều này là cần thiết vì một số máy chủ web được định cấu hình không chính xác và phân phát hình ảnh dưới dạng text/html, chẳng hạn.

Các tài nguyên dữ liệu bị chính sách CORB chặn sẽ được trình bày cho quy trình dưới dạng trống, mặc dù yêu cầu vẫn diễn ra ở chế độ nền. Do đó, trang web độc hại sẽ gặp khó khăn khi lấy dữ liệu trên nhiều trang web vào quy trình lấy cắp.

Để có được khả năng bảo mật tối ưu và hưởng lợi từ CORB, bạn nên làm như sau:

  • Đánh dấu các phản hồi bằng tiêu đề Content-Type chính xác. (Ví dụ: tài nguyên HTML phải được phân phát dưới dạng text/html, tài nguyên JSON có loại MIME JSON và tài nguyên XML có loại MIME XML).
  • Chọn không sử dụng tính năng đánh hơi bằng cách sử dụng tiêu đề X-Content-Type-Options: nosniff. Nếu không có tiêu đề này, Chrome sẽ phân tích nhanh nội dung để cố gắng xác nhận rằng loại nội dung đó là chính xác. Tuy nhiên, vì lỗi này xảy ra khi cho phép các phản hồi đi qua để tránh chặn các tệp như JavaScript, bạn nên tự xác nhận việc làm đúng.

Để biết thêm thông tin, hãy tham khảo bài viết về CORB dành cho nhà phát triển web hoặc nội dung giải thích chuyên sâu về CORB của chúng tôi.

Tại sao nhà phát triển web nên quan tâm đến tính năng Tách biệt trang web?

Trong hầu hết trường hợp, tính năng Cách ly trang web là một tính năng trình duyệt ở chế độ nền mà các nhà phát triển web không trực tiếp tiếp cận được. Ví dụ: không có API mới nào được hiển thị trên web để tìm hiểu. Nhìn chung, các trang web sẽ không thể phân biệt được khi chạy có hoặc không có tính năng Cách ly trang web.

Tuy nhiên, vẫn có một số ngoại lệ đối với quy tắc này. Việc bật tính năng Cách ly trang web sẽ có một số tác dụng phụ nhỏ có thể ảnh hưởng đến trang web của bạn. Chúng tôi duy trì danh sách các vấn đề đã biết về tính năng Cách ly trang web và trình bày chi tiết về những vấn đề quan trọng nhất ở bên dưới.

Bố cục toàn trang không còn đồng bộ nữa

Với tính năng Cách ly trang web, bố cục toàn trang không còn được đảm bảo là đồng bộ nữa vì các khung của một trang hiện có thể được phân bổ trên nhiều quy trình. Điều này có thể ảnh hưởng đến các trang nếu các trang đó giả định rằng một thay đổi về bố cục sẽ ngay lập tức được truyền đến tất cả các khung trên trang.

Ví dụ: hãy xem xét một trang web có tên fluffykittens.example giao tiếp với một tiện ích mạng xã hội được lưu trữ trên social-widget.example:

<!-- https://fluffykittens.example/ -->
<iframe src="https://social-widget.example/" width="123"></iframe>
<script>
  const iframe = document.querySelector('iframe');
  iframe.width = 456;
  iframe.contentWindow.postMessage(
    // The message to send:
    'Meow!',
    // The target origin:
    'https://social-widget.example'
  );
</script>

Ban đầu, chiều rộng của <iframe> của tiện ích mạng xã hội là 123 pixel. Tuy nhiên, trang FluffyKittens sẽ thay đổi chiều rộng thành 456 pixel (kích hoạt bố cục) và gửi thông báo đến tiện ích mạng xã hội có mã sau:

<!-- https://social-widget.example/ -->
<script>
  self.onmessage = () => {
    console.log(document.documentElement.clientWidth);
  };
</script>

Bất cứ khi nào tiện ích mạng xã hội nhận được thông báo thông qua API postMessage, tiện ích này sẽ ghi lại chiều rộng của phần tử <html> gốc.

Giá trị chiều rộng nào được ghi lại? Trước khi Chrome bật tính năng Tách biệt trang web, câu trả lời là 456. Việc truy cập vào document.documentElement.clientWidth sẽ buộc bố cục, bố cục này từng đồng bộ trước khi Chrome bật tính năng Cách ly trang web. Tuy nhiên, khi bạn bật tính năng Tách biệt trang web, việc bố cục lại tiện ích xã hội trên nhiều nguồn gốc sẽ diễn ra không đồng bộ trong một quy trình riêng. Do đó, câu trả lời hiện cũng có thể là 123, tức là giá trị width cũ.

Nếu một trang thay đổi kích thước của <iframe> trên nhiều nguồn gốc rồi gửi postMessage đến trang đó, thì với tính năng Cách ly trang web, khung nhận có thể chưa biết kích thước mới của trang khi nhận được thông báo. Nói chung, điều này có thể làm hỏng các trang nếu các trang đó giả định rằng một thay đổi về bố cục sẽ ngay lập tức được truyền đến tất cả các khung trên trang.

Trong ví dụ cụ thể này, một giải pháp mạnh mẽ hơn sẽ đặt width trong khung mẹ và phát hiện sự thay đổi đó trong <iframe> bằng cách theo dõi sự kiện resize.

Trình xử lý huỷ tải có thể hết thời gian chờ thường xuyên hơn

Khi một khung điều hướng hoặc đóng, tài liệu cũ cũng như mọi tài liệu khung con được nhúng trong đó đều chạy trình xử lý unload. Nếu thao tác điều hướng mới diễn ra trong cùng một quy trình kết xuất (ví dụ: đối với thao tác điều hướng cùng nguồn gốc), trình xử lý unload của tài liệu cũ và các khung con của tài liệu đó có thể chạy trong một khoảng thời gian dài tuỳ ý trước khi cho phép thao tác điều hướng mới thực hiện.

addEventListener('unload', () => {
  doSomethingThatMightTakeALongTime();
});

Trong trường hợp này, trình xử lý unload trong tất cả các khung đều rất đáng tin cậy.

Tuy nhiên, ngay cả khi không có tính năng Tách biệt trang web, một số thao tác điều hướng khung chính vẫn diễn ra trên nhiều quy trình, điều này ảnh hưởng đến hành vi của trình xử lý huỷ tải. Ví dụ: nếu bạn điều hướng từ old.example đến new.example bằng cách nhập URL vào thanh địa chỉ, thì thao tác điều hướng new.example sẽ diễn ra trong một quy trình mới. Trình xử lý tải xuống cho old.example và các khung con của trình xử lý này chạy trong quy trình old.example ở chế độ nền, sau khi trang new.example hiển thị và các trình xử lý tải xuống cũ sẽ bị chấm dứt nếu không hoàn tất trong một khoảng thời gian chờ nhất định. Vì trình xử lý giải phóng có thể không hoàn tất trước khi hết thời gian chờ, nên hành vi giải phóng sẽ kém tin cậy hơn.

Với tính năng Tách biệt trang web, tất cả thao tác điều hướng trên nhiều trang web sẽ trở thành thao tác trên nhiều quy trình, nhờ đó, các tài liệu trên nhiều trang web sẽ không chia sẻ quy trình với nhau. Do đó, trường hợp trên áp dụng trong nhiều trường hợp hơn và trình xử lý tải xuống trong <iframe> thường có các hành vi ở chế độ nền và hết thời gian chờ như mô tả ở trên.

Một điểm khác biệt khác do tính năng Cách ly trang web mang lại là thứ tự song song mới của trình xử lý tải xuống: nếu không có tính năng Cách ly trang web, trình xử lý tải xuống sẽ chạy theo thứ tự nghiêm ngặt từ trên xuống trên các khung. Nhưng với tính năng Tách biệt trang web, trình xử lý tải xuống sẽ chạy song song trên nhiều quy trình.

Đây là những hậu quả cơ bản của việc bật tính năng Tách biệt trang web. Nhóm Chrome đang nỗ lực cải thiện độ tin cậy của trình xử lý giải phóng tải cho các trường hợp sử dụng phổ biến (nếu có thể). Chúng tôi cũng nhận thấy một số lỗi trong đó trình xử lý tải khung con chưa thể sử dụng một số tính năng nhất định và đang nỗ lực để khắc phục các lỗi đó.

Một trường hợp quan trọng đối với trình xử lý huỷ tải là gửi ping kết thúc phiên. Việc này thường được thực hiện như sau:

addEventListener('pagehide', () => {
  const image = new Image();
  img.src = '/end-of-session';
});

Một phương pháp tốt hơn và hiệu quả hơn trong bối cảnh thay đổi này là sử dụng navigator.sendBeacon:

addEventListener('pagehide', () => {
  navigator.sendBeacon('/end-of-session');
});

Nếu cần kiểm soát nhiều hơn đối với yêu cầu, bạn có thể sử dụng tuỳ chọn keepalive của API Tìm nạp:

addEventListener('pagehide', () => {
  fetch('/end-of-session', {keepalive: true});
});

Kết luận

Tính năng Tách biệt trang web giúp các trang web không đáng tin cậy khó truy cập hoặc đánh cắp thông tin từ tài khoản của bạn trên các trang web khác bằng cách tách riêng từng trang web thành một quy trình riêng. Trong đó, CORB cố gắng loại bỏ các tài nguyên dữ liệu nhạy cảm khỏi quy trình kết xuất. Các đề xuất ở trên đảm bảo bạn khai thác tối đa các tính năng bảo mật mới này.

Cảm ơn Alex Moshchuk, Charlie Reis, Jason Miller, Nasko Oskov, Philip Walton, Shubhi Panicker và Thomas Steiner đã đọc bản nháp của bài viết này và đưa ra ý kiến phản hồi.