6.2 更加严格的内容安全策略

优质
小牛编辑
128浏览
2023-12-01

在讲解Chrome扩展的安全策略时,提到过其不允许inline-script,默认也不允许引用外部的JavaScript文件,而Chrome应用使用了更加严格的限制。

Chrome扩展和应用都使用了CSP(Content Security Policy)声明可以引用哪些资源,虽然之前我们并没有涉及到CSP的内容,但是Chrome扩展和应用会在我们创建时提供一个默认的值,对于Chrome扩展来说是script-src 'self'; object-src 'self'。上面的CSP规则表示只能引用自身(同域下)的JavaScript文件和自身的object元素(如Flash等),其他资源未做限定。

Chrome扩展允许开发者放宽一点点CSP的限制,即可以在声明权限的情况下引用https协议的外部JavaScript文件,如script-src 'self' https://ajax.googleapis.com; object-src 'self'。但是Chrome应用不允许更改默认的CSP设置。

那么CSP到底是什么呢?它是如何定义安全内容引用范围的?

CSP通常是在header或者HTML的meta标签中定义的,它声明了一系列可以被当前网页合法引用的资源,如果不在CSP声明的合法范围内,浏览器会拒绝引用这些资源,CSP的主要目的是防止跨站脚本攻击(XSS)。

CSP还是W3C草案,最新的1.1版文档还在撰写之中,所以在未来可能还会增加更多特性。目前CSP定义了9种属性,分别是connect-srcfont-srcframe-srcimg-srcmedia-srcobject-srcstyle-srcscript-srcdefault-srcconnect-src声明了通过XHR和WebSocket等方式的合法引用范围,font-src声明了在线字体的合法引用范围,frame-src声明了嵌入式框架的合法引用范围,img-src声明了图片的合法引用范围,media-src声明了声音和视频媒体的合法引用范围,object-src声明了Flash等对象的合法引用范围,style-src声明了CSS的合法引用范围,script-src声明了JavaScript的合法引用范围,最后default-src声明了未指定的其他引用方式的合法引用范围。

CSP的可选属性值有'self''unsafe-inline''unsafe-eval''none',这四个属性值都必须带引号代表特殊含义的值,分别表示允许引用同域资源、允许执行inline-script、允许执行字符串转换的代码(如在eval函数和setTimeout中的字符串代码)、不允许引用任何资源。

同时还支持host,如www.google.com表示可以引用www.google.com的资源,或者*.google.com允许引用google.com所有子域的资源(但不允许google.com根域的资源)。也可以声明只允许引用https下的资源,属性值声明为https:即可。或者声明只允许引用特定协议特定host的资源,如https://github.com*则代表任何资源,即不受限制。

Chrome应用默认的CSP规则为:

default-src 'self';
connect-src *;
style-src 'self' data: chrome-extension-resource: 'unsafe-inline';
img-src 'self' data: chrome-extension-resource:;
frame-src 'self' data: chrome-extension-resource:;
font-src 'self' data: chrome-extension-resource:;
media-src *;

也就是说在Chrome应用中,我们可以使用XHR请求任何资源;但是只能引用应用自身的CSS文件或者是dataURL转换的CSS文件和chrome-extension-resource协议下的CSS文件,同时我们可以在HTML直接写style代码块和在DOM中指定style属性;图片、嵌入式框架和字体只能引用自身或者dataURL转换的文件和chrome-extension-resource协议下的文件;可以引用任何音频和视频媒体资源;其他未指定的引用方式(object-srcscript-src)只能引用自身资源。

这么做显然会大大提高Chrome应用的安全性,防止被黑客利用盗取用户的数据,但也显然带来了新的问题。从Chrome应用的CSP规则中我们发现其不允许通过嵌入式框架引用外部资源,那么如果我们真的需要将一个外部页面展示在Chrome应用中怎么办呢?Google提供了webview标签代替iframe标签,使用webview标签必须指定大小和引用URL。

<webview src="http://news.google.com/" width="640" height="480"></webview>

同样Chrome应用也不允许引用外部的图片,但是我们可以通过XHR请求外部图片资源(XHR是可以请求到任何资源的,只要在Manifest中声明权限),然后通过转换成blob URL再添加到应用中。

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();

最后如果无法避免使用inline-scripteval等方式执行JavaScript代码,我们可以将“违规”的页面放入沙箱中执行,方法是在Manifest的sandbox中列出需要在沙箱中执行的页面。

"sandbox": {
    "pages": ["sandboxed.html"]
}