Content Security Policy (CSP)
为缓解潜在的大规模的跨站点脚本攻击问题,Chrome扩展系统已遵循 Content Security Policy (CSP)的理念,引入了严格的策略使扩展更安全,同时提供创建和实施策略规则的能力,这些规则用以控制扩展(或应用)能够加载的资源和执行的脚本。
通常情况下,CSP通过黑白名单的机制控制资源加载(或执行脚本)。为您的扩展制定一个合理的策略以使您认真地考虑哪些资源是扩展需要的,并让浏览器确保仅仅这些资源是您的扩展需要访问的。 这些策略为您的扩展提供host permissions之外的额外安全保障;这是一个额外的一层保护,而不是一种取代。
在Web上,此策略是通过HTTP头或meta
元素定义的。在Chrome扩展系统中,不存在这两种方式。扩展是通过manifest.json
文件定义的:
{ ..., "content_security_policy": "[POLICY STRING GOES HERE]" ... }
关于CSP语法的详细信息,请参考W3C的 Content Security Policy 规范。
默认策略限制
没有定义
manifest_version
的扩展安装包默认是没有内容安全策略的。定义manifest_version
为2的扩展才会默认开启内容安全策略。
script-src 'self'; object-src 'self'
此策略包含两条规则。这些规则都限制了扩展(或应用)的权限以增强安全:
不执行Inline JavaScript
Inline JavaScript和eval
一样危险,将不会被执行。这条规则将同时禁止内嵌<script>
块和内联事件(例如:
<button onclick="...">
)。
这条规则通过禁止第三方脚本避免大量的跨脚本攻击。同时它还强制您编写内容与表现分离的代码(这本就是您该做的,对吧?)。用个例子说明这一点:
假设您在一个单独的popup.html
文件中实现如下Browser Action弹出页:
<!doctype html> <html> <head> <title>My Awesome Popup!</title> <script> function awesome() { // do something awesome! } function totallyAwesome() { // do something TOTALLY awesome! } function clickHandler(element) { setTimeout("awesome(); totallyAwesome()", 1000); } </script> </head> <body> <button onclick="clickHandler(this)"> Click for awesomeness! </button> </body> </html>
为了使它能以您所希望的方式运行,结合本规则,需要做以下三个方面的修改:
-
clickHandler
的定义需移到外部JavaScript文件中(如:popup.js
)。 -
内联事件需通过
addEventListener
,并移到外部popup.js
文件中实现。 -
为了避免使用转换字符串到JavaScript的函数
"awesome(); totallyAwesome()"
的执行,setTimeout
调用需要重写。
修改之后将会像下面这样:
popup.js: ========= function awesome() { // Do something awesome! } function totallyAwesome() { // do something TOTALLY awesome! } function awesomeTask() { awesome(); totallyAwesome(); } function clickHandler(e) { setTimeout(awesomeTask, 1000); } // Add event listeners once the DOM has fully loaded by listening for the // `DOMContentLoaded` event on the document, and adding your listeners to // specific elements when it triggers. document.addEventListener('DOMContentLoaded', function () { document.querySelector('button').addEventListener('click', clickHandler); }); popup.html: =========== <!doctype html> <html> <head> <title>My Awesome Popup!</title> <script src="popup.js"></script> </script> </head> <body> <button>Click for awesomeness!</button> </body> </html>
只加载本地脚本和资源
只有扩展包内的脚本和资源才会被加载!通过Web即时下载的将不会被加载! 这确保您的扩展只执行已经打包在扩展之中的可信代码,从而避免了线上的网络攻击者通过恶意重定向您所请求的Web资源所带来的安全隐患。
在编写基于jQuery(或者其它库)的代码时,在扩展包中直接包含此库文件而不是从外部内容分发网络(CDN)在线加载。 换言之,不再这样使用:
<!doctype html> <html> <head> <title>My Awesome Popup!</title> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> </script> </head> <body> <button>Click for awesomeness!</button> </body> </html>
而是首先下载此js文件,并包含到扩展包里,然后修改代码为:
<!doctype html> <html> <head> <title>My Awesome Popup!</title> <script src="jquery.min.js"></script> </script> </head> <body> <button>Click for awesomeness!</button> </body> </html>
放宽默认策略
没有绕过“禁止Inline JavaScript执行”的办法。即使有意在脚本策略字段增加unsafe-inline也是没有任何作用的。就是这样设计的!
不过,如果您需要一些外部的JavaScript或者资源,您可以通过将HTTPS源的脚本加入白名单来放宽“只加载本地脚本和资源”策略。 请记住:白名单对于不安全的HTTP源是无效的。这也是特意设计的!因为必须确保可执行资源的加载正是您所期望的,而不是被网络攻击者替换过的。 而中间人在HTTP上已经是小菜一碟,且还很难检测到,因此只支持HTTPS源。
例如,允许加载来源自HTTS的example.com
网站的脚本,策略定义如下:
{ ..., "content_security_policy": "script-src 'self' https://example.com; object-src 'self'", ... }
请注意,上面的策略中,script-src
和object-src
都定义了。Chrome要求:必须定义这两者!如果您不知道怎么定义,就让它们都是'self'
。
通常,可以通过Google Analytics的统计结果来帮助定义策略。在brief tutorial 我们提供各种各样的扩展分析样板,和一个更详细的简短教程。
加固默认策略
您当然可以加强策略来提高安全性--这是以便利为代价的。
比如,default-src 'self'
使得扩展只能加载自己包内的资源(图片等),这种策略是适当的。
Mappy扩展就是一个处理超出默认安全策略的好例子。