到目前为止,我们把能用前端脚本防御 XSS 的方案都列举了一遍。

尽管看起来似乎很复杂累赘,不过那些是理论探讨而已,在实际中未必要都实现。我们的目标只是为了预警,能发现问题就行,并非要做到滴水不漏的程度。

事实上,HTML5 早已制定了一套浏览器 XSS 解决方案 —— Content Security Policy,并且大多主流浏览器实现了这个标准。

既然我们使用前端脚本重新实现一遍,因此得在各个方面占有优势。

兼容性

CSP 目前主流浏览器大多已支持,IE10、11 支持部分功能。对于 IE10 之前的,当然就束手无策了。如果使用前端脚本实现,可根据浏览器的实际能力进退。

对于第一篇介绍的 DOM-XSS,只要支持标准事件模型即可开启,因此兼容 IE9 完全可行。

事实上,IE8 就已开放了浏览器 API 接口,并支持原生访问器的操作。所以,IE8 是支持钩子程序,并能拦截可疑元素。

考虑到实际中,大多情况不做拦截,仅仅上报日志用以预警。对于这样低的需求,任何版本的浏览器都是完全可行的,甚至连 IE6 也没问题。

由于国内 IE 浏览器仍占有相当一部分比例,因此使用前端脚本的方案,能覆盖到更广的用户群体中。

部署

CSP 是通过 HTTP 头部实现的,策略配置储存在 Content-Security-Policy 这个字段里,因此得在 Web 服务器端进行配置。这对一些使用虚拟主机搭建的中小网站来说,配置起来比较麻烦。

而前端实现只需在页面里插入个脚本就行,完全不用关心后端的部署,修改策略也无需重启服务,维护起来容易的多。

不过,未来 CSP 会支持页面部署,通过 meta 标签即可配置策略,因此实用性会大幅提高。

当然,如今面临的各种问题,最终都能通过标准的完善和时代的进步而消失。所以任何方案都只是在解决当下的问题。

性能

毫无疑问,浏览器原生支持的肯定比模拟出来的更有效率。

之前考虑了各种情况,需安装各种事件和钩子,感觉很是累赘。不过,那只是理论上防御最严密的情况,现实中基本只作预警,并不需监控全开。

作为测试,我们还是考虑最严密的情况。根据前几篇文章探讨的结果,我们做一个原型演示

为了能线下模拟在线产品,同时做了一个 Chrome 插件,将脚本注入到在线页面里:

页面中使用到的脚本、插件、网络通信等,都在控制台里监控到,并且根据策略匹配显示不同的颜色。

再来看性能影响。尽管我们开启了所有的监控,但初始化消耗的时间,仍可接受。(测试环境 i3 2.3G 的笔记本 Win7 64位)

毕竟,JavaScript 的钩子仅仅是修改变量的字段而已,并非像传统语言那样得修改内存权限等等。

当然,这个页面内容比较少,只能看出脚本初始化的情况。

我们换个内容非常多的页面:

由于嵌套了框架页,在讨论钩子的时候我们提到,新的页面环境也需防御,因此触发了多次『主动防御』的初始化。

『静态扫描』的内容,正是被 MutationObserver 捕获的元素。由于页面内容非常多,静态元素也是随着 HTML 文档边下载边展现的。尽管扫描累计时间并不少,但相对整个页面加载的数秒时间,也基本忽略不计了。

『动态扫描』的内容,则是后期通过脚本创建的。随着滚动条往下拉,扫描次数也逐渐增多。由于我们勾住了 createElement ,理论上说调用会慢一些。不过现实中很少会一口气大量调用该方法的,大多使用模板通过 innerHTML 批量创建。

另外,我们还勾住了 setAttribute 这个常用的方法,统计结果和『访问器钩子』一起纳入在『属性检验』里。不过,现实中大多场合并不需要调用这个方法,毕竟从 attribute 到 property 还得经过一次字符串的解析,能直接用 property 则完全没必要去 setAttribute。

而访问器钩子,只有在修改 script、embed 这些元素的 src 属性时才会触发,这些操作本来就很少,因此属性扫描的额外消耗还是可以忽略的。

策略配置

使用脚本最大的优势就在于,其策略可以灵活配置。规则可以动态产生,匹配也不限模式,通配符或是正则都可以。本来一切都是脚本实现的,何去何从完全也可由脚本决定。

当然,为了更好的适应 CSP 标准,我们尽可能的将策略规范与标准靠近,以便相互兼容。

因为脚本的灵活性,我们不仅支持通配符来匹配站点名,正则表达式也是完全支持。同时为了方便测试,调试控制台里可以动态修改策略。

下面,我们找个存在 XSS 的页面,立即来试验下:

刷新,XSS 执行了:

虽然是非同源执行的,但好歹也算个 XSS。我们就那它来测试。

接着开启我们的防火墙,为可执行模块配上白名单策略。只允许当前站点的资源,其他的则拦截,并且发送报警日志:

出现奇迹的时刻到来了。。。

站外的可疑模块成功拦截了!同时开始发送预警日志到后台。

日志上报

标准的 CSP 中,上报的格式是固定的,并且信息内容也有限。但对于脚本来说,这些都不是问题,随时可以添加想要获得的信息。

你肯定会觉得,上报的数量不会太多,存在漏洞的毕竟只是少数。不过,广义上的 XSS 未必都是由漏洞引起的。

XSS —— Cross Site Script,只要是页面里的站外的脚本,都可以算是。通常情况下只能由漏洞引起,但在一些特殊的场合,任意页面都可能出现站外脚本,例如之前讨论的流量劫持,或是浏览器插件,都是很常见的情况。

所以,我们除了能在线预警外,还能统计各个地区运行商的广告劫持,以及一些网页外挂插件。

当然,想绕过也是很容易的。只要在流量上过滤了我们的防御脚本,或是屏蔽日志发送,我们都是无从得知的。

后记

事实上,最终的方案已上线。尽管只抽样了极少量的用户,但仍传回上百万的预警日志。几乎所有都是广告劫持和浏览器插件,即使存在漏洞暂时也无法得知,我们不可能一个个去分析复现。因此,我们还需一套高效的复现系统,来帮助我们实现自动化的复现工作。

XSS 前端防火墙(5): 整装待发的更多相关文章

  1. XSS前端防火墙

    前一段时间,在EtherDream大神的博客里看到关于XSS防火墙的一系列文章,觉得很有意思.刚好科创要做一个防火墙,就把XSS前端防火墙作为一个创新点,着手去实现了. 在实现过程中,由于各种原因,比 ...

  2. XSS 前端防火墙 —— 整装待发

    到目前为止,我们把能用前端脚本防御 XSS 的方案都列举了一遍. 尽管看起来似乎很复杂累赘,不过那些是理论探讨而已,在实际中未必要都实现.我们的目标只是为了预警,能发现问题就行,并非要做到滴水不漏的程 ...

  3. XSS 前端防火墙(1):内联事件拦截

    关于 XSS 怎样形成.如何注入.能做什么.如何防范,前人已有无数的探讨,这里就不再累述了.本文介绍的则是另一种预防思路. 几乎每篇谈论 XSS 的文章,结尾多少都会提到如何防止,然而大多万变不离其宗 ...

  4. XSS 前端防火墙 —— 可疑模块拦截

    上一篇介绍的系统,已能预警现实中的大多数 XSS 攻击,但想绕过还是很容易的. 由于是在前端防护,策略配置都能在源代码里找到,因此很快就能试出破解方案.并且攻击者可以屏蔽日志接口,在自己电脑上永不发出 ...

  5. XSS 前端防火墙(2):可疑模块拦截

    由于是在前端防护,策略配置都能在源代码里找到,因此很快就能试出破解方案.并且攻击者可以屏蔽日志接口,在自己电脑上永不发出报警信息,保证测试时不会被发现. 昨天提到最简单并且最常见的 XSS 代码,就是 ...

  6. XSS 前端防火墙 —— 天衣无缝的防护

    上一篇讲解了钩子程序的攻防实战,并实现了一套对框架页的监控方案,将防护作用到所有子页面. 到目前为止,我们防护的深度已经差不多,但广度还有所欠缺. 例如,我们的属性钩子只考虑了 setAttribut ...

  7. XSS 前端防火墙 —— 无懈可击的钩子

    昨天尝试了一系列的可疑模块拦截试验,尽管最终的方案还存在着一些兼容性问题,但大体思路已经明确了: 静态模块:使用 MutationObserver 扫描. 动态模块:通过 API 钩子来拦截路径属性. ...

  8. XSS 前端防火墙(3):无懈可击的钩子

    昨天尝试了一系列的可疑模块拦截试验,尽管最终的方案还存在着一些兼容性问题,但大体思路已经明确了: 静态模块:使用 MutationObserver 扫描. 动态模块:通过 API 钩子来拦截路径属性. ...

  9. XSS 前端防火墙(4):天衣无缝的防护

    例如,我们的属性钩子只考虑了 setAttribute,却忽视还有类似的 setAttributeNode.尽管从来不用这方法,但并不意味人家不能使用. 例如,创建元素通常都是 createEleme ...

随机推荐

  1. Android核心分析之二十八Android GDI之Surface&Canvas

    Surface&Canvas Canvas为在画布的意思.Android上层的作图几乎都通过Canvas实例来完成,其实Canvas更多是一种接口的包装.drawPaints ,drawPoi ...

  2. 简单的自绘CListBox(多行显示)(覆盖DrawItem函数,然后用CDC绘制)

    之前写过一个自绘的CListBox类,详细请参考http://blog.csdn.net/VisualEleven/archive/2010/10/12/5935430.aspx现在修改这之前的代码, ...

  3. Centos挂载windows共享文件夹

    1.windows7共享一个文件夹(1)新建一个用户:devin,密码:admin123(2)在E盘新建一个文件夹,share,并设置共享 对用户devin共享,并让其权限为:读取和写入. 2.lin ...

  4. 传统三层结构和MVC之于贫血模式和充血模式以及领域建模

      相信很多人跟我一样,一开始在使用贫血模式的三层结构:抽象出来一个贫血的实体封装,然后把对模型的所有操作,分离出来,分离到BLL层去,然后DALL层负责把这些操作和数据库产生映射,负责读写删改的操作 ...

  5. 阿里Druid数据库连接池使用

    阿里巴巴推出的国产数据库连接池,据网上测试对比,比目前的DBCP或C3P0数据库连接池性能更好 可以监控连接以及执行的SQL的情况. 加入项目的具体步骤: 1.导入jar <parent> ...

  6. HDU 4662 MU Puzzle 简单找规律

    没有任何变换(III变U和删UU操作)之前,I 的个数一定是2^x个(也就是2的整数次幂) 若仅考虑III变U,那么设U的个数为k,I 的个数变为2^x-3*k 再加上删除UU操作,假设我们删除了2* ...

  7. 每天一个小算法(Shell sort5)

    希尔排序的关键在于步长的选取. 希尔排序的复杂度比较复杂,主要跟步长的选择有关,大概是 O(n logn^2),一般认为就是介于 O(n^2) 和 O(n logn) 之间.最好步长比较复杂,一般第一 ...

  8. NDK(5) Android JNI官方综合教程[JavaVM and JNIEnv,Threads ,jclass, jmethodID, and jfieldID,UTF-8 and UTF-16 Strings,Exceptions,Native Libraries等等]

    JNI Tips In this document JavaVM and JNIEnv Threads jclass, jmethodID, and jfieldID Local and Global ...

  9. Simple Factory vs. Factory Method vs. Abstract Factory【简单工厂,工厂方法以及抽象工厂的比较】

    I ran into a question on stackoverflow the other day that sort of shocked me. It was a piece of code ...

  10. 手机号段、ip地址归属地大全,最新手机号段归属地,IP地址归属地数据库

    百事通:http://www.114best.com/dh/114.aspx?w=17097232323,联通识别为电信的,1349错 二三四五:http://tools.2345.com/frame ...