Hệ thống tiện ích của Chrome thực thi một Chính sách bảo mật nội dung (CSP) mặc định khá nghiêm ngặt.
Các hạn chế trong chính sách rất đơn giản: tập lệnh phải được chuyển ra ngoài dòng thành riêng biệt
Bạn phải chuyển đổi các tệp JavaScript, trình xử lý sự kiện cùng dòng để sử dụng addEventListener
và eval()
là
tắt. Ứng dụng Chrome có chính sách nghiêm ngặt hơn nữa và chúng tôi khá hài lòng với việc bảo mật
thuộc tính mà các chính sách này cung cấp.
Tuy nhiên, chúng tôi nhận ra rằng nhiều thư viện sử dụng các cấu trúc giống eval()
và eval
, chẳng hạn như
new Function()
để tối ưu hoá hiệu suất và dễ biểu đạt. Các thư viện tạo mẫu đang
đặc biệt ưa chuộng phong cách triển khai này. Trong khi một số (như Angular.js) hỗ trợ CSP
của hộp này, nhiều khung làm việc phổ biến vẫn chưa được cập nhật lên cơ chế tương thích với
tiện ích Thế giới ít hơn eval
. Do đó, việc ngừng hỗ trợ chức năng đó đã chứng minh nhiều hơn
khó khăn hơn dự kiến đối với nhà phát triển.
Tài liệu này giới thiệu hộp cát là một cơ chế an toàn để đưa các thư viện này vào dự án của bạn mà không ảnh hưởng đến tính bảo mật. Tóm lại, chúng ta sẽ sử dụng toàn bộ thuật ngữ phần mở rộng, nhưng khái niệm này áp dụng như nhau cho các ứng dụng.
Tại sao là hộp cát?
eval
nguy hiểm bên trong một tiện ích vì mã mà tiện ích này thực thi có quyền truy cập vào mọi nội dung trong
môi trường có quyền cao của tiện ích. Hiện có nhiều API chrome.*
mạnh mẽ có thể
ảnh hưởng nghiêm trọng đến tính bảo mật và quyền riêng tư của người dùng; đánh cắp dữ liệu đơn giản là điều ít lo lắng nhất của chúng tôi.
Giải pháp được cung cấp là một hộp cát trong đó eval
có thể thực thi mã mà không cần truy cập vào
dữ liệu của tiện ích hoặc API có giá trị cao của tiện ích. Không có dữ liệu, không API, không sao cả.
Chúng tôi thực hiện việc này bằng cách liệt kê các tệp HTML cụ thể bên trong gói tiện ích dưới dạng hộp cát.
Bất cứ khi nào trang hộp cát được tải, trang đó sẽ được chuyển đến một nguồn gốc duy nhất và sẽ bị từ chối
quyền truy cập vào các API chrome.*
. Nếu tải trang hộp cát này vào tiện ích của mình qua iframe
, chúng ta có thể
chuyển tin nhắn, để công cụ hành động dựa trên những thông điệp đó theo cách nào đó và chờ đợi báo cáo chuyển lại cho chúng ta
kết quả. Cơ chế nhắn tin đơn giản này cung cấp cho chúng tôi mọi thứ cần thiết để đảm bảo an toàn, bao gồm cả ứng dụng dựa trên eval
trong quy trình làm việc của tiện ích.
Tạo và sử dụng hộp cát.
Nếu bạn muốn đi thẳng vào mã, hãy tải tiện ích mẫu hộp cát và tận hưởng tắt. Đây là ví dụ hoạt động về một API nhắn tin nhỏ, được xây dựng dựa trên Thanh công cụ thư viện mẫu này và nó sẽ cung cấp cho bạn mọi thứ bạn cần để bắt đầu. Dành cho những ai Một chút thông tin giải thích nữa, hãy cùng xem qua mẫu đó ở đây.
Liệt kê tệp trong tệp kê khai
Mỗi tệp lẽ ra phải được chạy bên trong một hộp cát phải được liệt kê trong tệp kê khai tiện ích bằng cách thêm một
Thuộc tính sandbox
. Đây là một bước quan trọng và rất dễ quên nên hãy kiểm tra kỹ để đảm bảo
tệp hộp cát của bạn được liệt kê trong tệp kê khai. Trong mẫu này, chúng ta đang tạo hộp cát cho tệp một cách khéo léo
có tên là "sandbox.html". Mục kê khai sẽ có dạng như sau:
{
...,
"sandbox": {
"pages": ["sandbox.html"]
},
...
}
Tải tệp trong hộp cát
Để thực hiện tác vụ thú vị với tệp hộp cát, chúng ta cần tải tệp trong ngữ cảnh
có thể xử lý được bằng mã của tiện ích. Tại đây, sandbox.html đã được tải vào
trang Sự kiện của tiện ích (eventpage.html) qua iframe
. eventpage.js chứa mã
gửi thông báo vào hộp cát bất cứ khi nào người dùng nhấp vào hành động của trình duyệt bằng cách tìm iframe
trên trang và thực thi phương thức postMessage
trên contentWindow
. Thông điệp là một đối tượng
chứa hai thuộc tính: context
và command
. Chúng ta sẽ tìm hiểu về cả hai phần này sau giây lát.
chrome.browserAction.onClicked.addListener(function() {
var iframe = document.getElementById('theFrame');
var message = {
command: 'render',
context: {thing: 'world'}
};
iframe.contentWindow.postMessage(message, '*');
});
postMessage
, hãy xem tài liệu về postMessage
về MDN . Cuốn sách này khá đầy đủ và đáng đọc. Đặc biệt, lưu ý rằng dữ liệu chỉ có thể được truyền qua lại nếu dữ liệu đó theo tuần tự. Ví dụ: Hàm thì không.Làm việc gì đó nguy hiểm
Khi được tải, sandbox.html
sẽ tải thư viện Tay cầm, đồng thời tạo và biên dịch một nội dung cùng dòng
theo cách mà Thanh điều khiển đề xuất:
<script src="handlebars-1.0.0.beta.6.js"></script>
<script id="hello-world-template" type="text/x-handlebars-template">
<div class="entry">
<h1>Hello, !</h1>
</div>
</script>
<script>
var templates = [];
var source = document.getElementById('hello-world-template').innerHTML;
templates['hello'] = Handlebars.compile(source);
</script>
Cách này không thành công! Mặc dù Handlebars.compile
kết thúc bằng new Function
nhưng mọi thứ vẫn hoạt động
chính xác như mong đợi và chúng ta sẽ tạo được một mẫu được biên dịch trong templates['hello']
.
Trả lại kết quả
Chúng tôi sẽ cung cấp mẫu này để bạn sử dụng bằng cách thiết lập một trình nghe thông báo chấp nhận các lệnh
trên Trang sự kiện. Chúng tôi sẽ sử dụng command
được truyền vào để xác định việc cần làm (bạn có thể
hãy hình dung bạn làm nhiều việc khác ngoài việc kết xuất hình ảnh; có thể là tạo mẫu không? Bạn nên quản lý chúng theo
không?), và context
sẽ được truyền trực tiếp vào mẫu để hiển thị. HTML được hiển thị
sẽ được trả về Trang sự kiện để tiện ích có thể làm điều gì đó hữu ích với tiện ích này sau này:
<script>
window.addEventListener('message', function(event) {
var command = event.data.command;
var name = event.data.name || 'hello';
switch(command) {
case 'render':
event.source.postMessage({
name: name,
html: templates[name](event.data.context)
}, event.origin);
break;
// case 'somethingElse':
// ...
}
});
</script>
Quay lại Trang sự kiện, chúng ta sẽ nhận được thông báo này và sẽ thực hiện một số thao tác thú vị với html
mà chúng tôi đã truyền. Trong trường hợp này, chúng tôi sẽ chỉ nhắc lại thông qua Thông báo trên màn hình, nhưng
bạn hoàn toàn có thể sử dụng HTML này một cách an toàn như một phần trong giao diện người dùng của tiện ích. Chèn thông qua
innerHTML
không gây ra rủi ro bảo mật đáng kể, thậm chí là sự xâm phạm hoàn toàn của hộp cát
mã thông qua một số cuộc tấn công thông minh sẽ không thể chèn nội dung trình bổ trợ hoặc tập lệnh nguy hiểm vào
ngữ cảnh tiện ích quyền cao.
Cơ chế này giúp việc tạo mẫu trở nên đơn giản, nhưng tất nhiên không chỉ giới hạn ở việc tạo mẫu. Bất kỳ hạng nào mã không hoạt động tốt theo Chính sách bảo mật nội dung nghiêm ngặt có thể được đặt trong hộp cát; inch trên thực tế, các thành phần hộp cát của tiện ích sẽ chạy chính xác theo thứ tự thường hữu ích để hạn chế mỗi phần của chương trình ở tập hợp đặc quyền nhỏ nhất cần thiết để chương trình thực thi đúng cách. Bản trình bày Viết ứng dụng web an toàn và tiện ích của Chrome của Google I/O 2012 đưa ra một số ví dụ điển hình về kỹ thuật này trong thực tiễn và đáng giá 56 phút bất cứ lúc nào.