XSS终结者Content-Security-Policy
Roy Lv7

CSP全称为Content Security Policy,即内容安全策略。主要以白名单的形式配置可信任的内容来源,在网页中,能够使白名单中的内容正常执行(JS,CSS,image等),而非白名单的内容无法正常执行,从而减少跨站脚本攻击(XSS),当然也能够减少运营商劫持的内容注入攻击

example:

不支持CSP的浏览器将会自动忽略CSP的信息,不会有什么影响。

浏览器兼容性查询caniuse

CSP 语法组成

策略类型

csp有两种策略类型:

  • Conten-Security-Policy

  • Content-Security-Policy-Report-Only

    这两种策略类型的主要区别也i可以从命名上看出,第一种对不安全的资源会进行阻止,第二种只会进行数据上报,不会有实际的阻止。

    当定义多个策略的时候,浏览器会优先采用最先定义的。

指令集合

CSP的指令是指组成内容来源白名单的关键,上面两种策略类型含有以下

指令示例及说明

指令 取值示例 说明
default-src ‘self’ cdn.example.com 定义针对所有类型(js/image/css/web font/ajax/iframe/多媒体等)资源的默认加载策略,某类型资源如果没有单独定义策略,就使用默认。
script-src ‘self’ js.example.com 定义针对JavaScript的加载策略
object-src ‘self’ 针对,, 等标签的加载策略
style-src ‘self’ css.example.com 定义针对样式的加载策略
img-src ‘self’ image.example.com 定义针对图片的加载策略
media-src ‘media.example.com’ 针对或者引入的html多媒体等标签的加载策略
frame-src ‘self’ 针对iframe的加载策略
connect-src ‘self’ 针对Ajax、WebSocket等请求的加载策略。不允许的情况下,浏览器会模拟一个状态为400的响应
font-src font.qq.com 针对Web Font的加载策略
sandbox allow-forms allow-scripts 对请求的资源启用sandbox
report-uri /some-report-uri 告诉浏览器如果请求的资源不被策略允许时,往哪个地址提交日志信息。不阻止任何内容,可以改用Content-Security-Policy-Report-Only头
base-uri ‘self’ 限制当前页面的url(CSP2)
child-src ‘self’ 限制子窗口的源(iframe、弹窗等),取代frame-src(CSP2)
form-action ‘self’ 限制表单能够提交到的源(CSP2)
frame-ancestors ‘none’ 限制了当前页面可以被哪些页面以iframe,frame,object等方式加载(CSP2)
plugin-types application/pdf 限制插件的类型(CSP2)

指令值示例及说明

指令值 示例 说明
* img-src * 允许任何内容
‘none’ img-src ‘none’ 不允许任何内容
‘self’ img-src ‘self’ 允许同源内容
data: img-src data: 允许data:协议(如base64编码的图片)
www.a.com img-src www.a.com 允许加载指定域名的资源
*.a.com img-src *.a.com 允许加载a.com任何子域的资源
https://img.com img-src https://img.com 允许加载img.com的https资源
https: img-src https: 允许加载https资源
‘unsafe-inline’ script-src ‘unsafe-inline’ 允许加载inline资源(style属性,onclick,inline js和inline css等等)
‘unsafe-eval’ script-src ‘unsafe-eval’ 允许加载动态js代码,例如eval()

CSP的使用方式

HTML Meta标签

在这种形式中,Meta标签主要含有两部分的key-value:

  • http-equiv
  • content

http-equiv的value为CSP的策略类型,而content则是声明指令集合,即白名单。如

在HTML的head标签中添加上面的Meta标签,当浏览器支持CSP标准时,Content-Security-Policy实际阻止策略将会使得非同源的script(根据指令集合来定)不会被加载及执行。

Meta标签的Content-Security-policy-Report-Only方式在当前(2020/10)多数移动端浏览器上表现正常,但是不推荐这样做,在Chrome 50 会产生如下的提示

The report-only Content Security Policy xxxxxxx was delivered via a element,which is disallowed. The policy has been ignored.

HTTP Header

通过Meta的方式很是简单,但当涉及到页面较多时,使用Meta标签的方式需要在每个页面都鸽子加上。如果通过服务端配置HTML返回的响应头HTTP Header带上CSP的指令的话,那将能够一劳永逸,同事支持多个页面。下面为响应头

Response Header

Connection: keep-alive

Content-Security-Policy: script-src ‘self’ *.qq.com *.url.cn

不仅如此,这种形式的Content-Security-Policy-Report-Only方式能够得到更好的兼容支持,也是推荐方式。

实践经验

CSP的阻止加载及执行的方式相当强大,也因为它如此强大,所以在使用时更是要小心谨慎,毕竟,如果一个不小心制定了错误的指令集合方案,那将可能导致阻止了正常文件的加载,影响业务功能,这是相当危险的。

一步步制定你的CSP方案

1. 通过HTML Meta标签进行初步方案的制定(meta标签已不支持report-uri 2019.7)

这种方式实现成本低,只对当前的HTML有效,从而能够进行逐步灰度。当然存在上面提及的兼容性问题,但如果现在时移动端上,或者在可逾期的浏览器内核上跑的话,在兼容性满足的情况下,那还是可以用过这个方式进行Report-Only。结合自己业务的资源情况以及在Chrome上调试制定初步方案。

2. 使用HTTP Header的Content-Security-Policy-Report-Only方式进一步确定方案

由于上面的Meta标签存在一定的兼容问题,所以当我们制定了初步方案后,就可以开始使用HTTP Header的形式,小心使得万年船,这里还是建议先使用Report-Only的方式,并制定上报的url来收集阻止的内容,通过上报的数据进行方案的优化,从而进一步确定具体方案。

3.HTTP Header改用Content-Security-Policy策略进行实际拦截阻止

具体的CSP方案经过上面两轮洗礼,在分析完上报的数据,确定白雾疏漏后,可将HTTP Header改用Content-Security-Policy策略,从而进行实际拦截阻止。

项目实践数据

从过腾讯使用CSP后的上报拦截数据

日期 CSP阻止量 在线PV 占比
2016.03.31 23431 545872 4.31%
2016.04.01 24459 619979 3.95%
2016.04.02 20398 525055 3.88%
2016.04.02 19938 475985 4.19%
2016.04.03 23140 507329 4.56%

从上面的数据可以看出,每天被攻击的情况呈现出一种稳定持续的倾向,而且这类攻击一版不是针对某个业务的,具备了普遍性,这样的影响范围可想而知。

参考

https://www.w3.org/TR/CSP/#changes-from-level-1
http://w3c.github.io/webappsec-csp/
Content-Security-Policy Header ⟶ CSP Reference & Examples
Content Security Policy 1.0Content Security Policy Level 3
Content Security Policy Level 3
Content-Security-Policy Header ⟶ CSP Reference & Examples
Content Security Policy 1.0

  • 本文标题:XSS终结者Content-Security-Policy
  • 本文作者:Roy
  • 创建时间:2020-10-22 09:31:57
  • 本文链接:https://www.yrzdm.com/2020/10/22/csp-xss/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!