Chrome 应用安全模型不允许在 iframe 中使用外部内容以及使用内嵌脚本和 eval()
。您可以替换这些限制,但您的外部内容必须与应用隔离开来。
被隔离的内容无法直接访问应用的数据或任何 API。使用跨源 XMLHttpRequests 和后消息传递在事件页面和沙盒化内容之间进行通信,并间接访问 API。
引用外部资源
应用使用的内容安全政策不允许使用多种远程网址,因此您无法在应用页面中直接引用外部图片、样式表或字体。您可以改为使用跨源 XMLHttpRequests 获取这些资源,然后通过 blob:
网址传送这些资源。
清单要求
为了能够执行跨源 XMLHttpRequests,您需要为远程网址的主机添加权限:
"permissions": [
"...",
"https://supersweetdomainbutnotcspfriendly.com/"
]
跨域 XMLHttpRequest
将远程网址提取到应用中,并将其内容作为 blob:
网址提供:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://supersweetdomainbutnotcspfriendly.com/image.png', true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
var img = document.createElement('img');
img.src = window.URL.createObjectURL(this.response);
document.body.appendChild(img);
};
xhr.send();
您可能需要在本地保存这些资源,以便离线使用。
嵌入外部网页
利用 webview
标记,您可以在应用中嵌入外部 Web 内容,例如网页。它取代了指向远程网址的 iframe,远程网址在 Chrome 应用中处于停用状态。与 iframe 不同,webview
标记在单独的进程中运行。这意味着,内部利用的漏洞仍会被隔离,并且无法获取提升的权限。此外,由于其存储(Cookie 等)与应用是隔离开来的,因此 Web 内容无法访问应用的任何数据。
添加 WebView 元素
您的 webview
元素必须包含源内容的网址,并指定其尺寸。
<webview src="http://news.google.com/" width="640" height="480"></webview>
更新媒体资源
如需动态更改 webview
标记的 src
、width
和 height
属性,您可以直接在 JavaScript 对象上设置这些属性,也可以使用 setAttribute
DOM 函数。
document.querySelector('#mywebview').src =
'http://blog.chromium.org/';
// or
document.querySelector('#mywebview').setAttribute(
'src', 'http://blog.chromium.org/');
沙盒本地内容
沙盒环境允许在沙盒化的唯一来源中提供指定的页面。然后,这些网页将不受其内容安全政策的约束。沙盒化页面可以使用 iframe、内嵌脚本和 eval()
。请查看sandbox的清单字段说明。
不过,需要权衡操作:沙盒化页面无法使用 Chrome。*API。如果您需要执行 eval()
等操作,请通过此路由豁免 CSP,但您将无法使用炫酷的新功能。
在沙盒中使用内嵌脚本
下面是一个使用内嵌脚本和 eval()
的沙盒化网页示例:
<html>
<body>
<h1>Woot</h1>
<script>
eval('console.log(\'I am an eval-ed inline script.\')');
</script>
</body>
</html>
在清单中包含沙盒
您需要在清单中添加 sandbox
字段,并列出要在沙盒中提供的应用页面:
"sandbox": {
"pages": ["sandboxed.html"]
}
在窗口中打开沙盒化页面
与任何其他应用页面一样,您也可以创建一个窗口,以便在其中打开沙盒化页面。以下示例会创建两个窗口,一个用于未沙盒化的主应用窗口,另一个用于沙盒化页面:
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('window.html', {
'bounds': {
'width': 400,
'height': 400,
'left': 0,
'top': 0
}
});
chrome.app.window.create('sandboxed.html', {
'bounds': {
'width': 400,
'height': 400,
'left': 400,
'top': 0
}
});
});
在应用页面中嵌入沙盒化页面
您也可以使用 iframe
将沙盒化页面嵌入到其他应用页面中:
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<p>I am normal app window.</p>
<iframe src="sandboxed.html" width="300" height="200"></iframe>
</body>
</html>
向沙盒化页面发送消息
发送消息的过程分为两个部分:您需要从发送者页面/窗口发布消息,并在接收页面/窗口中监听消息。
发布消息
您可以使用 postMessage
在您的应用与沙盒化内容之间进行通信。下面的后台脚本示例会将消息发布到所打开的沙盒化页面:
var myWin = null;
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('sandboxed.html', {
'bounds': {
'width': 400,
'height': 400
}
}, function(win) {
myWin = win;
myWin.contentWindow.postMessage('Just wanted to say hey.', '*');
});
});
一般来说,在网络上,您需要指定邮件发送的确切来源。 Chrome 应用无权访问沙盒化内容的唯一来源,因此您只能将所有来源添加为可接受的来源(“*”)。在接收端,您通常需要检查来源;但由于 Chrome 应用内容已包含,因此没有必要这样做。如需了解详情,请参阅 window.postMessage。
收听消息和回复
以下是添加到沙盒化网页的消息接收器示例:
var messageHandler = function(event) {
console.log('Background script says hello.', event.data);
// Send a reply
event.source.postMessage(
{'reply': 'Sandbox received: ' + event.data}, event.origin);
};
window.addEventListener('message', messageHandler);
如需了解详情,请查看sandbox示例。