SharedArrayBuffer cuối cùng cũng đã hoạt động trở lại trên trình duyệt, nhưng nó chỉ hoạt động khi trang web được cô lập cross-origin – một trạng thái yêu cầu hai header phản hồi. Việc thêm các header này đã buộc tôi phải loại bỏ mọi script bên thứ ba trên trang web của mình, một bước đi đã định hình lại cách toàn bộ front end được xây dựng và những dữ liệu mà nó bị rò rỉ.
Tại sao các header này lại quan trọng
SharedArrayBuffer cho phép đa luồng thực thụ trong JavaScript, một điều kiện tiên quyết để chạy ffmpeg bên trong một tab. Các trình duyệt hiện đại đã kích hoạt lại tính năng này sau các biện pháp giảm thiểu kiểu Spectre, nhưng họ đã gắn nó với việc cô lập cross-origin. Để đạt được sự cô lập đó, máy chủ phải gửi:
Cross-Origin-Opener-Policy: same-originCross-Origin-Embedder-Policy: require-corp
Header thứ hai, require-corp, thông báo cho trình duyệt rằng bất kỳ tài nguyên bên ngoài nào cũng phải mang header Cross-Origin-Resource-Policy hoặc được truy xuất bằng CORS (Cross-Origin Resource Sharing). Hầu hết các dịch vụ bên thứ ba không thiết lập các header này, vì vậy các script, font và iframe của họ sẽ bị chặn hoàn toàn.
Những gì đã mất đi khi bật chế độ cô lập
Ngay khi các header được áp dụng, một chuỗi các lỗi đã xuất hiện:
- Analytics – hầu hết các nhà cung cấp tải mã theo dõi của họ bằng một thẻ
<script>đơn giản thực hiện yêu cầu no-CORS. Nếu không có header CORP, yêu cầu sẽ bị từ chối, khiến trình theo dõi không bao giờ chạy được. - Google Fonts – stylesheet được tải từ
fonts.googleapis.commà không có CORS. Trình duyệt sẽ loại bỏ nó, khiến trang web mất đi kiểu chữ tùy chỉnh. - Phương tiện nhúng – các iframe YouTube và script widget thiếu CORP, vì vậy chúng ngừng hiển thị.
- Các cửa sổ pop-up OAuth – mối quan hệ
window.openerbị phá vỡ bởi chính sách same-origin nghiêm ngặt, làm hỏng luồng đăng nhập thông qua pop-up thông thường.
Nói tóm lại, bất kỳ tài nguyên nào dựa vào một tên miền bên thứ ba đều biến mất trừ khi tên miền đó chấp nhận chế độ header mới.
Xây dựng lại mà không cần các bên trung gian
Đối mặt với một trang web bị lỗi, tôi đã viết lại stack front-end xoay quanh các tài nguyên tự lưu trữ (self-hosted):
- Fonts và hình ảnh hiện được phục vụ từ chính origin của tôi, loại bỏ nhu cầu sử dụng stylesheet bên ngoài.
- Data APIs được xây dựng trên một backend riêng mà tôi kiểm soát, vì vậy mọi yêu cầu đều nằm trong tên miền của tôi.
- Analytics được chuyển thành một Cloudflare Worker nhỏ gọn, chấp nhận các sự kiện
POSTvà lưu trữ chúng trong một bucket riêng. Phía client chỉ là vài dòng mãfetch. - Các công cụ báo lỗi và ghi lại phiên làm việc (session replay) như Sentry đã bị loại bỏ hoàn toàn; bất kỳ lỗi crash nào giờ đây đều được ghi lại vào endpoint của riêng tôi.
Nếu vẫn cần một tài nguyên bên ngoài, con đường khả thi duy nhất là proxy nó thông qua một máy chủ mà bạn sở hữu, thêm header CORP cần thiết trước khi trình duyệt nhìn thấy nó.
Lợi ích về quyền riêng tư so với chi phí vận hành
Lợi ích tức thì là rất rõ ràng: trang web không còn rò rỉ dữ liệu sử dụng cho các mạng quảng cáo, nhà cung cấp font hoặc các nền tảng video. Mọi dữ liệu telemetry đều nằm dưới sự kiểm soát của tôi, và tôi có thể xóa chúng bất cứ khi nào tôi muốn. Mức độ quyền riêng tư đó rất khó đạt được với stack bên thứ ba điển hình.
Sự đánh đổi là gánh nặng bảo trì bổ sung. Việc lưu trữ font, xử lý lưu trữ analytics và duy trì một proxy luôn cập nhật là những tác vụ mà hầu hết các nhà phát triển thường thuê các dịch vụ chuyên dụng. Cách tiếp cận này cũng đồng nghĩa với việc mất đi các tính năng mà các dịch vụ đó cung cấp – ví dụ như tổng hợp lỗi theo thời gian thực hoặc trực quan hóa phễu (funnel) chi tiết.
Quan điểm ngược lại: liệu hệ sinh thái có thích nghi không?
Một số người lập luận rằng các nhà cung cấp bên thứ ba cuối cùng sẽ thêm các header bắt buộc, giúp việc áp dụng cô lập cross-origin trở nên dễ dàng. Một số ít đã làm điều đó, nhưng đa số các dịch vụ được sử dụng rộng rãi vẫn chưa. Cho đến khi hệ sinh thái bắt kịp, các nhà phát triển phải quyết định liệu lợi ích về quyền riêng tư có xứng đáng với nỗ lực kỹ thuật cần thiết để tự lưu trữ hay không.
Cách xác minh bạn thực sự đã được cô lập
Trước khi bắt đầu viết lại, hãy xác nhận trình duyệt coi trang của bạn là đã được cô lập:
crossOriginIsolated // should be true
typeof SharedArrayBuffer // should be "function"
Nếu một trong hai kiểm tra thất bại, các header đang không được áp dụng chính xác, và SharedArrayBuffer sẽ vẫn không khả dụng.
Bước tiếp theo cho các nhà phát triển là gì?
Khi có nhiều ứng dụng web tìm kiếm sự gia tăng hiệu suất từ JavaScript đa luồng, áp lực lên các nhà cung cấp bên thứ ba trong việc áp dụng CORP sẽ tăng lên. Trong thời gian chờ đợi, bất kỳ dự án nào cần SharedArrayBuffer nên lập kế hoạch cho một chiến lược tài nguyên tự lưu trữ hoặc một lớp proxy nhẹ. Việc theo dõi các ghi chú phát hành của trình duyệt về những thay đổi trong yêu cầu cô lập cũng sẽ rất thiết yếu.
Điểm mấu chốt: Việc kích hoạt cross-origin isolation để mở khóa SharedArrayBuffer buộc người dùng phải đưa ra một lựa chọn khó khăn – giữ lại sự tiện lợi của các tập lệnh bên thứ ba hoặc đánh đổi lấy một mô hình quyền riêng tư chặt chẽ và tự kiểm soát hơn. Quyết định này định hình lại cả kiến trúc kỹ thuật lẫn dấu chân luồng dữ liệu của các trang web hiện đại.
