Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 3.0 License, and code samples are licensed under the BSD License.
©2012 Google
为了缓解很大一部分潜在的跨站脚本问题,Chrome浏览器的扩展程序系统引入了 内容安全策略(CSP) 的一般概念。这将引入一些相当严格的策略,会使得扩展程序在默认情况下更加安全,并向您提供创建并强制应用一些规则,管理您的扩展程序和应用程序允许载入的内容类型。
大体上,CSP以白名单/黑名单的机制对您的扩展程序载入或执行的资源起作用。为您的扩展程序定义一项合理的策略使您仔细考虑您的扩展程序需要的资源,并且使浏览器确保您的扩展程序只能访问指定的那些资源。这些策略提供了比您的扩展程序请求的主机权限 更高的安全性,它们是额外的保护层,而不是主机权限的替代品。
在网页中,这样的策略通过HTTP头信息或者meta
元素定义。在Chrome浏览器的扩展程序系统中,它们都不是合适的方式。扩展程序的策略通过扩展程序的
manifest.json
文件定义,如下所示:
{ ..., "content_security_policy": "[策略字符串写在这里]" ... }
有关CSP语法的完整详情,请参见 内容安全策略规范 (英文),还可参考HTML5Rocks上的内容安全策略简介 (英文)这篇文章。
没有定义
manifest_version
(清单文件版本)
的扩展程序包没有默认的内容安全策略,而选择
manifest_version
2的扩展程序具有如下默认的内容安全策略:
script-src 'self'; object-src 'self'
这一策略通过三种方式限制扩展程序和应用程序,来增强安全性:
如下所示的代码不能工作:
alert(eval("foo.bar.baz")); window.setTimeout("alert('hi')", 10); window.setInteral("alert('hi')", 10); new Function("return foo.bar.baz");
像这样对JavaScript字符串求值是一种常见的XSS攻击载体,而您应该编写如下所示的代码:
alert(foo && foo.bar && foo.bar.baz); window.setTimeout(function() { alert('hi'); }, 10); window.setInterval(function() { alert('hi'); }, 10); function() { return foo && foo.bar && foo.bar.baz };
内嵌JavaScript代码将不会执行。这一限制既禁用了内嵌的
<script>
块,同时也包括内嵌的事件处理函数(例如<button onclick="...">
).
第一个限制使您不可能意外地执行任何恶意的第三方提供的脚本,彻底消除了一大部分的跨站脚本攻击。然而,这也确实要求您在编写代码时清晰地将内容与行为分开(这也是您当然应该做的吧?)。举一个例子可能会更加清楚,您可能想要编写一个包含如下内容的
popup.html
,作为
浏览器按钮的弹出内容
<!doctype html> <html> <head> <title>我做的很棒的弹出内容!</title> <script> function awesome() { // 做些很棒的事情! } function totallyAwesome() { // 做些棒极了的事情! } function clickHandler(element) { setTimeout("awesome(); totallyAwesome()", 1000); } function main() { // 在这里进行初始化工作。 } </script> </head> <body onload="main();"> <button onclick="clickHandler(this)"> 单击看看会发生什么! </button> </body> </html>
三个地方需要修改,才能使以上代码按照您预期的方式工作:
clickHandler
定义需要移至外部的JavaScript文件中(例如popup.js
就不错)。
内嵌的事件处理定义必须通过
addEventListener
重写并放在popup.js
中。
如果您目前仍然通过类似于
<body onload="main();">
的代码开始执行您的程序,请考虑通过监听文档的
DOMContentLoaded
事件或window的
load
事件来替换它,选择哪一种取决于您的需要。下面我们将使用前一种形式,因为通常它能够更快触发。
setTimeout
调用需要重写,避免将字符串"awesome(); totallyAwesome()"
转换为JavaScript来执行。做出这些更改后代码如下所示:
popup.js: ========= function awesome() { // 做些很棒的事情! } function totallyAwesome() { // 做些棒极了的事情! } function awesomeTask() { awesome(); totallyAwesome(); } function clickHandler(e) { setTimeout(awesomeTask, 1000); } function main() { // 在这里进行初始化工作。 } // 通过监听文档的`DOMContentLoaded`事件在DOM 完全载入后添加事件处理函数, // 当事件触发时向指定元素添加您自己的事件处理函数。 document.addEventListener('DOMContentLoaded', function () { document.querySelector('button').addEventListener('click', clickHandler); main(); });
popup.html: =========== <!doctype html> <html> <head> <title>我做的很棒的弹出内容!</title> <script src="popup.js"></script> </head> <body> <button>单击看看会发生什么!</button> </body> </html>
脚本与对象资源只能从扩展程序包中载入,不能从网上载入。这样确保您的扩展程序只会执行您确实允许的代码,避免任何主动的网络攻击者,恶意地重定向您对资源的请求。
不要编写依赖于外部CDN载入的jQuery(或其它库)的代码,而应该考虑将特定版本的jQuery包含在您的扩展程序包中。即,不要:
<!doctype html> <html> <head> <title>我做的很棒的弹出内容!</title> <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script> </head> <body> <button>单击看看会发生什么!</button> </body> </html>
而应该下载此文件,包括在您的扩展程序包中,并编写如下代码:
<!doctype html> <html> <head> <title>我做的很棒的弹出内容!</title> <script src="jquery.min.js"></script> </head> <body> <button>单击看看会发生什么!</button> </body> </html>
您无法放宽限制,允许执行内嵌JavaScript代码。特别地,设置包含
'unsafe-inline'
的脚本策略不会生效。
如果您需要某些外部JavaScript代码或对象资源,您可以在有限的程度上放宽策略,将安全来源的可接受脚本加入白名单。我们希望确保以扩展程序提升的权限载入的可执行资源一定是您预期的,而没有被主动的网络攻击者替换。由于
中间人攻击
非常普遍,并且通过HTTP无法检测到,其他来源不会被接受。目前,我们允许将来源为以下协议的资源加入白名单:
HTTPS
, chrome-extension
和
chrome-extension-resource
.
为了方便开发,我们也允许将那些通过HTTP从本地计算机服务器上载入的资源列入白名单,您可以将
http://127.0.0.1
或
http://localhost
任意端口上的脚本和对象来源加入白名单。
对于通过HTTP载入资源的限制仅仅适用于直接执行的那些资源,您仍然可以,例如,向您希望使用的任何来源发起XMLHttpRequest连接,默认策略不会以任何方式限制
connect-src
或者其它任何CSP指示符。
允许通过HTTPS载入来自
example.com
放宽策略定义如下所示:
"content_security_policy": "script-src 'self' https://example.com; object-src 'self'"
注意script-src
与object-src
都由这一策略定义,Chrome浏览器不会接受不将这些值限制为(至少)
'self'
的策略。
利用Google Analytics(分析)是这一种策略定义的典型例子,这样的情况很常见,所以我们在 利用Google Analytics(分析)追踪事件 的示例扩展程序中提供了简单例子,并在 简明教程中提供了更多详情。
阻止eval()
及类似构造,
setTimeout(String)
, setInterval(String)
以及
new Function(String)
的策略也可以通过向您的策略添加
'unsafe-eval'
来放松:
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
然而我们强烈建议您不要这么做。这些函数是臭名昭著的XSS攻击载体。
您当然也可以以带来更多不变为代价,使用您的扩展程序允许的更严格的策略,增强安全性。例如,要指定您的扩展程序只能从自己的包中载入
所有类型(如图片等)的资源,可以使用这样的策略:default-src 'self'
Mappy示例扩展程序就是使用的策略比默认设置更加严格的例子。