Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

XSS终结者-CSP理论与实践 #5

Open
joeyguo opened this issue May 18, 2016 · 12 comments
Open

XSS终结者-CSP理论与实践 #5

joeyguo opened this issue May 18, 2016 · 12 comments

Comments

@joeyguo
Copy link
Owner

joeyguo commented May 18, 2016

原文地址

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

示例:在 HTML 的 Head 中添加如下 Meta 标签,将在符合 CSP 标准的浏览器中使非同源的 script 不被加载执行。

<meta http-equiv="Content-Security-Policy" content="script-src 'self'">

不支持 CSP 的浏览器将自动会忽略 CSP 的信息,不会有什么影响。具体兼容性可在caniuse查看

CSP 语法组成

策略类型

CSP 有两种策略类型:

  • Content-Security-Policy
  • Content-Security-Policy-Report-Only

这两种策略类型的主要区别也可以从命名上看出,第一种对不安全的资源会进行阻止执行,而第二种只会进行数据上报,不会有实际的阻止。
当定义多个策略的时候,浏览器会优先采用最先定义的。

指令集合

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' 针对或者
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 则是声明指令集合,即白名单。如

<meta http-equiv="Content-Security-Policy" content="script-src 'self'">

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

Meta 标签的 Content-Security-Policy-Report-Only 方式在当前(2016/5/19)多数移动端浏览器上表现正常,但是 不推荐 这样做,如 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 的指令的话,那将能够一劳永逸,同时支持多个页面。下图为响应头

http

不仅如此,这种形式的 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 上报拦截,通过上报的数据可以看到日均劫持达到 20000+ 的量,这对于页面本身 PV 并非很高的情况,在线 PV 占比竟达到了 4%;另一方面,从数据上也可以看出 拦截的主要来源(如下表)

3月1日-4月4日,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.03 19938 475985 4.19%
2016.04.04 23140 507329 4.56%

4月4日,CSP 拦截的 URL 前5名

排名 被 拦截的 URL CSP拦截量
1 http://wap.zjtoolbarc60.10086.cn:8080 5410
2 http://wap.toolbar.sd.chinamobile.com:8080 2690
3 http://119.188.105.1:8080 1498
4 http://211.137.132.89:9090 947
5 http://n.cosbot.cn 675

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

不过,这也侧面烘托出 CSP 的强大,简单处理就能够阻止如此多的攻击,赶紧接入吧。

参考

https://www.w3.org/TR/CSP/#changes-from-level-1
http://w3c.github.io/webappsec-csp/
http://content-security-policy.com/
https://www.w3.org/TR/2012/CR-CSP-20121115/

查看更多文章 >>
https://github.com/joeyguo/blog

@joeyguo joeyguo changed the title XSS终结者-CSP理论与实践 XSS的终结-CSP理论与实践 May 19, 2016
@joeyguo joeyguo changed the title XSS的终结-CSP理论与实践 XSS终结者:CSP理论与实践 May 19, 2016
@joeyguo joeyguo changed the title XSS终结者:CSP理论与实践 XSS终结者-CSP理论与实践 May 19, 2016
@ksky521
Copy link

ksky521 commented Jul 19, 2016

哈哈,万能的zjtoolbar

@joeyguo
Copy link
Owner Author

joeyguo commented Jul 19, 2016

@ksky521 6到不行 :)

@chenpengjun
Copy link

服务端配置 HTML 返回的响应头 HTTP header
请问这个怎么配置,我们现在就遇到成都联通4G劫持的问题,导致网页打不开,项目用到的技术是spa react基于微信公众号开发的,配置了meta标签没有用,方便说下具体的解决方案吗

@joeyguo
Copy link
Owner Author

joeyguo commented May 25, 2017

@chenpengjun 这个响应头的设置方式跟其他响应头是一样呀。跟技术栈关系不大,可以先检查下meta标签的规则是否正确,如果有监控系统的话,可以从数据进行分析。

@chenpengjun
Copy link

chenpengjun commented May 26, 2017

html添加meta标签,nginx配置了http Content-Security-Policy,经过测试发现没有用,后来改为https就解决了。具体的错误信息http://119.188.105.1:8080。加载失败导致网页打不开显示空白页。还是有点疑惑,为什么我这边按照你的思路配置还是不行,是哪里出了问题吗

@joeyguo
Copy link
Owner Author

joeyguo commented Jul 6, 2017

@chenpengjun 具体需要看看是否返回头信息正常,与被劫持插入的文件是否有关系。https是从另外的角度在解决劫持的问题

@DongZhouJone
Copy link

亲。。请教个问题,前端本地写了meta, 如何实践呢。有没有可以看的demo,或者成型的网页,我看了写资料,就发现twitter上有CSP应用,国内有么。目前有这么个项目需求,实在是不知道怎么继续了- -。而且report-uri 好像只有后台可以配,感觉只有前端单方面不能做。。

@joeyguo
Copy link
Owner Author

joeyguo commented Nov 20, 2017

@DongZhouJone 加了meta后,加载一些非白名单的资源,就可以看到报错,并且可以看到上报请求,report-uri 是指明一个上报地址,这是由后台服务提供,收集信息。

@DongZhouJone
Copy link

DongZhouJone commented Nov 21, 2017

sir, 重新看了初始文档,原来report-uri 在meta中会被忽略,那就是实践的话只能同过后台配置内容安全的请求头了吧,那上报只能后台测试?

@lou1swu
Copy link

lou1swu commented Jan 26, 2018

经过尝试,我发现使用http-header的形式也存在兼容问题(支持ie10+),基于我们的业务是兼容到ie6的,请问是不是用csp来避免xss的方式就不适用了呢

@nilptr
Copy link

nilptr commented Apr 8, 2018

请问在您实践中有没有出现正式部署 CSP 后,上报数量逐渐变少的情况?

@joeyguo
Copy link
Owner Author

joeyguo commented Apr 10, 2018

@nilptr 不做处理时,上报量没有变少趋势。不过上报量并不是每天一致,时多时少。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants