Content Security Policy
本文以 MDN 为参考
CSP 兼容旧的浏览器,即在不支持它的浏览器上依旧能够正常地加载网页。如果使用不支持它的浏览器加载网站,浏览器则会使用标准的同源策略。
启用 CSP,你需要设置你的网络服务器使其返回一个 Content-Security-Policy
HTTP header(有时候你可能会看见有提及 X-Content-Security-Policy
的文章,但是这是一个过去的版本,所以你不必设置这个 Header)。
另外,你也可以使用 <meta> 标签来配置 CSP,例如:<meta http-equiv="Content-Security-Policy" content="default-src 'self'; image-src https:*; child-src 'none';">
优势
防止大部分 XSS 跨站脚本攻击
使用 CSP 的最大好处就是可以有效地防止并且上报绝大多数 XSS 攻击。XSS 攻击利用了浏览器信任从服务器上获取的数据这一特点。恶意脚本会被受害者的浏览器所执行,因为浏览器信任从服务器上获取到的内容,即使看起来不是从正常的地方来的。
CSP 通过指定浏览器应该从哪一个域名加载合法的脚本,为减少或消除 XSS 提供了可能。兼容 CSP 的浏览器只会执行从 CSP 信任的来源获取到的脚本,并将其他的脚本忽略(包括内联脚本和 HTML 事件处理标记)。
一个终极的保护方法是禁用所有的脚本执行。(这句话不是我说的啊)
防止包嗅探攻击
除了限制可以加载资源的域名,服务器也可以指定应该使用哪一种协议,例如,并且从安全角度推荐,指定所有的资源必须通过 HTTPS 进行加载,这是最吼的。一个完整的数据传输安全策略不仅包括了强制使用 HTTPS,还包括了为所有 cookies 设置 secure flag 并且能够使页面自动从 HTTP 跳转到 HTTPS。同时,网站还应该使用 HSTS 来确保浏览器只使用加密的通道进行连接。
使用 CSP
配置 CSP 时需要为网页添加 Content-Security-Policy
HTTP header,并且指定一个值来控制资源的加载。例如,一个上传并且显示图片的页面可以允许从所有地方加载图片,但限制表单提交的地址。一个适当的 CSP 可以很好地保护页面免遭 XSS 攻击。这篇文章介绍了如何正确地构造这样的 headers,并且附有示例代码。
指定你的策略
你可以使用 CSP 的 HTTP header 来指定你的策略,像这样:
其中的 policy 是一个描述策略的字符串指令。
制定策略
策略通过一系列字段来描述,每一个字段都包含了资源类型或策略范围。你的策略应该包含一个用于未被指明资源类型的 default-src 字段。一个策略需要包含一个 default-src 或 script-src 字段来阻止内联脚本的运行,也可以阻止 eval()
的使用。同时,一个策略需要包含一个 default-src 或 style-src 字段来阻止从 <style>
或者 style
属性加载样式。
实例:常见的用法
这一节提供了一些常见的策略方案。
实例 1
网站管理员希望所有的资源都从当前站点加载(但是这不包括子域名)
实例 2
网站管理员希望从一个信任的域名及其子域名加载资源(与当前网站不同源的域名)
实例 3
网站管理员希望允许用户从任何来源引用图片,但是音频 / 视频只能从信任的提供方获取,而且所有的脚本只能从指定服务器获取。
在这里,默认地,内容只能从当前来源加载,除了下面的例外:
- 图片可以从任何地方加载(注意
*
通配符) - 媒体只允许从 media1.com 和 media2.com 上获取(并且不包括子域名)
- 可执行脚本只允许从 userscripts.example.com 加载
实例 4
网银的网站管理员希望确保所有的内容都通过 SSL 进行加载以防攻击者窃听网络流量。
这样只允许通过 HTTPS 从 onlinebanking.jumbobank.com 加载内容。
实例 5
邮箱的网站管理员希望允许邮件中的 HTML,同时图片可以从任意地方获取,但不能有 JavaScript 或者其他潜在的不安全因素。
注意这个例子没有指定 script-src。通过这一个例子,站点使用的是 default-src,这意味着所有脚本只能从当前站点获取。
测试你的策略
CSP 可以被设置为 report-only
模式。这个策略不会被执行,但是这样可以将所有浏览器拦截到的攻击报告至提供的 URI。另外,使用 report-only
模式还可以方便新策略的测试。
你可以设置 Content-Security-Policy-Report-Only HTTP header 来指定你的策略,像这样:
如果 Content-Security-Policy-Report-Only 和 Content-Security-Policy Header 在同一个相应中出现,两种策略都会被采用。这时候 Content-Security-Policy 会被执行,而 Content-Security-Policy-Report-Only 只是指定了报告的条件,并不会影响页面的加载。
支持 CSP 的浏览器一般都会将检测到的攻击报告给服务器,但你的策略必须指定一个 report-uri 字段。
启用攻击报告
默认地,攻击不会被报告。想要启用攻击报告,你需要在策略中指定 report-uri 字段,提供至少一个处理报告的 URI:
然后你需要配置你的服务器来处理这些报告。
攻击报告的语法
攻击报告是一个 JSON 对象,包含了以下字段:
攻击报告实例
让我们看看一个位于 http://example.com/signup.html 的页面。它使用了如下的策略,只允许从 cdn.example.com 上加载样式表:
HTML 的代码如下
你能发现哪里有错误吗?样式表只被允许从 cdn.example.com 上加载,然而这个网页希望从自己的源(http://example.com)上加载。捕获到这一“攻击”的浏览器会向提供的地址通过 POST 请求发送攻击报告,像这样:
所见即所得,这个报告包含了被阻止的 URI。但这并不一定是这样的,当试图从 http://anothercdn.example.com/stylesheet.css 加载样式表时,报告不会发送完整的路径,报告中只会有协议、主机和端口(http://anothercdn.example.com)。W3 给出了这一[奇怪特性的解释](http://www.w3.org/TR/CSP/#violation-reports)。总之,这防止了向非同源地址发送请求时泄露敏感信息。
浏览器兼容性
桌面系统
特性 | Chrome | Edge | FireFox | IE | Opera | Safari | Servo |
---|---|---|---|---|---|---|---|
Content-Security-Policy | 251 | 14 | 23.02 | 103 | 15 | 74 | ? |
Content-Security-Policy-Report-Only | 25 | 14 | 23.0 | 10 | 15 | 7 | ? |
- 在 Chrome 14 中通过
X-Webkit-CSP
实现。 - 在 FireFox 4 中通过
X-Content-Security-Policy
实现。 - 通过
X-Content-Security-Policy
实现,只支持sandbox
字段。 - 在 Safari 6 中通过
X-Webkit-CSP
实现。
手机系统
特性 | Android | Chrome For Android | Edge Mobile | FireFox for Android | IE Mobile | Opera Mobile | Safari Mobile |
---|---|---|---|---|---|---|---|
Content-Security-Policy | 4.4 | (Yes) | (Yes) | 23.0 | ? | ? | 7.11 |
Content-Security-Policy-Report-Only | 4.4 | (Yes) | (Yes) | 23.0 | ? | ? | 7.1 |
- 在 IOS 5.1 中通过
X-Webkit-CSP
实现。
参考资料
- Content-Security-Policy
- Content-Security-Policy-Report-Only
- Content Security in WebExtensions
- Display security and privacy policies In Firefox Developer Tools
(^o^)/~ 本文已完成。