资讯专栏INFORMATION COLUMN

利用 onload 事件监控跨站资源

leone / 1607人阅读

摘要:我们通过事件捕获机制,将其拿下,从而监控文档级别的全局事件。我们也可同时将其捕获,跟踪那些暂时不可用的跨站资源。不过本文的主题已经说了,只是监控跨站资源而已,并不拦截。转自利用事件监控跨站资源

说到跨站资源监控,首先会联想到『Content Security Policy』。既然 CSP 好用,我们何必自己再搞一套呢。那就先来吐槽下 CSP 的缺陷。

目前的 CSP 日志不详细

用过 CSP 的都很郁闷,上报的只有违规的站点名,却没有具体路径。这是缺陷,还是特意的设计?

显然,CSP 是为安全定制的,里面的规范自然要严格制定,否则就会带来新的安全问题。如果支持详细路径的上报,那又会引出什么问题?

由于 CSP 会上报所有的请求,甚至包括重定向的,因此可以用来探测重定向后的地址。假如已登录的用户访问 login.xx.com 会重定向到 xx.com/username,那么攻击者设计一个只允许重定向前的规则的页面,用户访问后,重定向后的 URL 就会当做违规地址上报给攻击者,这其中就包括了用户名。

如果支持详细路径的上报,这简直就是灾难,就用来探测的用户隐私信息了。事实上目前只上报主机名,都能进行一些利用,例如这篇 Using Content-Security-Policy for Evil。

不过新的规范总是在改进,未来也许只上报重定向前的 URL。但在这之前,我们只能接受这些鸡肋的上报日志。

规则不灵活

CSP 目前只支持白名单列表,这多少有些死板。

更糟的是,不同规则之间无法继承和共享。例如默认有个 default-src 规则,但其他的规则会覆盖它,而不是继承它。这就导致各个规则之间,出现很多的重复,使得整个字符串变的冗长。

无法和页面交互

CSP 的监控和上报,是在浏览器后台自动处理的,没有提供一个事件供页面进行交互。

这样就只能使用统一方式强制处理了,而无法交给页面脚本,更好的来自定义处理。

上报方式不可控

如果处理方式有多种选择,那么统一处理也无可厚非。

但事实上 CSP 的上报方式及格式,没有任何可选余地。只能使用 POST + JSON 的方式提交,并且其中的字段十分累赘,甚至把规则里的白名单列表也发上来了。

此外,也无法设定一个缓存时间,控制重复上报的间隔。在配置白名单遗漏时,会出现大量的误报,严重消耗资源。

浪费带宽

在较新的 Chrome 里,能够使用 meta 标签在前端页面定义 CSP 规则,但其他浏览器目前仍不支持。

为了能够统一,大多仍使用 HTTP 头部输入的方式。由于规则通常都很长,导致每次页面访问,都会额外增加数百字节。

维护繁琐

如果是通过 Web 服务开启的,那么每次调整策略,都得修改配置甚至重启服务,很是麻烦。

兼容性不高

目前只有高版本的浏览器支持,而 IE 系列的则几乎都没能很好的支持。

如果某些攻击只争对低版本的浏览器,那么很有可能出现大量遗漏。

模拟的 CSP 原理

事实上在 CSP 出现的好几年前,就有一个能够监控跨站资源的方案,下面就来分享下。

写过 JS 的都知道,如果需要给大量元素监听事件,无需对每个元素上都进行绑定,只要监听它们的容器即可。当具体的事件冒泡到容器上,通过 event.target 即可获知是哪个元素产生的。

脚本、图片、框架等元素加载完成时,都会产生 onload 事件;而所有元素都位于『文档』这个顶级容器。因此我们监听 document 的 onload 事件,即可获知所有加载资源的元素。

不过 onload 这个事件比较特殊,无法通过冒泡的方式来监听。但在 DOM-3 标准模型里,事件还有一个『捕获』的概念,这也是为什么 addEventListener 有第三个参数的原因。

我们通过事件捕获机制,将其拿下,从而监控文档级别的全局 onload 事件。



类似的,如果资源加载失败,会触发 onerror 事件。我们也可同时将其捕获,跟踪那些暂时不可用的跨站资源。

优势

通过脚本的方式,就可以更灵活的处理问题了。规则的黑白名单,上报方式、格式等等,都可以自己来定义。最重要的是,我们能够获得详细的违规 URL 了!

相比后端配置,前端脚本更新维护起来容易的多。而且得益于浏览器缓存,无需每次更新配置,节省很多资源。

增强

也许你已经发现了,这只能实现 CSP 的 Report-Only 功能,根本无法进行拦截。而且其他的内联事件、网络通信等也没有涉及。

不过本文的主题已经说了,只是监控跨站资源而已,并不拦截。事实上,如果能够做到及时发现问题,就很不错了。

如果非得通过 JS 来实现拦截功能,可以参考之前的『XSS 前端防火墙系列』:

内联事件拦截

跨站资源拦截

网络通信拦截

虽然可以更严格的防护,但实现起来更臃肿,性能开销也更大。要是拦截了正常的业务功能,造成的损失会更大。

而使用如何这个小技巧,只需几行代码即可实现,性能消耗忽略不计。

缺陷

当然,那么简单的方案肯定无法全面。

由于我们只监听文档容器,有些还未加入到文档的元素产生的事件,我们就无法捕获到了。最典型的就是:

new Image().src = "..."

虽然创建的 HTMLImageElement 对象具有 onload 事件,但是此时还只是一个离屏元素,事件就无法对外传播了。

如果非得解决,只能通过函数钩子的方式监控 URL。

此外,IE9 以下的浏览器不支持 DOM-3,而 attachEvent 是无法设置捕获的,因此我们还需一个后备方案。毕竟国内低版本 IE 用户仍有不少,即使能实现部分功能,也胜于无。

后备

事实上,即使主流浏览器,有些特殊元素并没有 onload 事件,例如 Flash 插件。

为了弥补这些不足,同时尽可能保持简单高效,我们使用定时轮询的方式,对特定元素进行扫描。这里使用一个大家都知道,但未必都清楚的方法:document.getElementsByTagName。

这个功能都知道,但返回的类型或许很少琢磨。他返回的并不是一个 Array,也不是 NodeList,而是 HTMLCollection。

在 W3C 规范描述中,有一个显眼的词 『live』,已经道出了这个接口的独特之处——它是一个动态的集合,能随着容器内元素的增减而变化。

因此,我们事先映射出文档容器内的元素,之后即可随时查询集合了。




除了 SCRIPT,我们还可以监控所有存在风险隐患的元素,例如:EMBED,OBJECT,IFRAME 等等。这样即使是低版本的 IE 用户,也能参与预警上报了,比起完全没有好的多。

当然,这种简单方法也很容易被绕过。如果脚本删除了自身元素,那么我们就无法跟踪到了。而脚本一旦运行就已在内存里,即使元素节点被移除,仍然能继续运行。

不过,对于一般的情况也足够应对了。通常运行商的广告劫持,大多都很落后。即使要进行后期对抗,也可以利用之前的前端防火墙,使用严格的方案。

扩展信息

见过 CSP 日志的大多都会很困惑,出现的这些违规资源,究竟位于页面何处。由于没有确切的细节,给排查工作带来很大困难。

毕竟,绝大多数的上报问题,都是无法复现的。它们要么是运行商的广告,或者是浏览器插件。难很通过这些日志,来定位问题所在。

既然如今使用自己的脚本来实现,理应带上一些有意义的信息。除了资源类型和详细 URL,我们还需要一个能够定位问题所在的参数——DOM 路径。

将每层元素的 #id 和 .class 跟随标签名,得到一个标准的 CSS 选择器。通过它,即可非常容易的定位到违规元素,同时也能用于统计和分析。

例如出现顶级元素就是 SCRIPT 的,显然这是一个被插入到 之外的脚本,很有可能就是运营商注入的广告脚本。

例如出现 HTML > BODY > ... > DIV.editor-post > SCRIPT 这样帖子容器里的脚本,那么极有可能是出现 XSS 了。正常情况下,用户内容区域并不会出现脚本元素。

通过详细的上报日志不断学习,后端即可越来越精准的分析出问题所在。

而这些,目前的 CSP 难以实现。

上报方式

吸取 CSP 报告的不足之处,我们使用更灵活的方式。

对于运营商广告那样的跨站资源,反复上报同样的信息,是毫无意义的,只会浪费带宽资源。对于同一类警告,一定时间内上报一次就后够了。

利用 URL、DOM 路径等信息,可以更容易的将日志进行客户端去重。通过本地存储的记录,就不必每次都上报了,在本地记录违规的次数即可。

对于不严重的警告,本地也可以累计到一定的数量再上报。这样多条日志一次发送,即可大幅减轻后端压力。甚至还可以考虑压缩内容,节省网络带宽。

只有让前端进行负载维护,才不至于大规模部署的场合下,接收端被海量的误报日志拖垮。

总结

尽管 CSP 的初衷很美好,但到如今,仍只是能用,并没有做到好用。因此,实际面临的问题,还是得靠自己来解决。

当然,标准的制定本来就是受益于大众的,我们也希望 CSP 标准能发展的越来越好用。

转自:利用 onload 事件监控跨站资源

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/85515.html

相关文章

  • 慕课网js面试题学习笔记(ES6 标准) ——实时更新

    摘要:而第一种方法只能判断引用类型,不能判断值类型,因为值类型没有对应的构造函数描述一个对象的过程生成一个新的空对象指向这个新对象执行构造函数中的代码,即对赋值将新对象的属性指向构造函数的属性返回,即得到新对象。 最近在在看前端面试教程,这篇文章里大部分是看视频的过程中自己遇到的不清楚的知识点,内容很简单,只是起到一个梳理作用。有些地方也根据自己的理解在作者的基础上加了点东西,如有错误,欢迎...

    netmou 评论0 收藏0
  • XSS跨站脚本攻击

    摘要:三攻击分类反射型又称为非持久性跨站点脚本攻击,它是最常见的类型的。存储型又称为持久型跨站点脚本,它一般发生在攻击向量一般指攻击代码存储在网站数据库,当一个页面被用户打开的时候执行。例如,当错误,就会执行事件利用跨站。 一、简介 XSS(cross site script)是指恶意攻击者利用网站没有对用户提交数据进行转义处理或者过滤不足的缺点,进而添加一些代码,嵌入到web页面中去。使别...

    BingqiChen 评论0 收藏0
  • XSS跨站脚本攻击

    摘要:三攻击分类反射型又称为非持久性跨站点脚本攻击,它是最常见的类型的。存储型又称为持久型跨站点脚本,它一般发生在攻击向量一般指攻击代码存储在网站数据库,当一个页面被用户打开的时候执行。例如,当错误,就会执行事件利用跨站。 一、简介 XSS(cross site script)是指恶意攻击者利用网站没有对用户提交数据进行转义处理或者过滤不足的缺点,进而添加一些代码,嵌入到web页面中去。使别...

    zsirfs 评论0 收藏0
  • HTML应用安全

    摘要:通常编写过滤器验证用户输入时,过滤器应该是基于白名单已知的安全结构配置编写,允许白名单通过,不允许其他输入而基于黑名单已知的不安全结构配置编写,即允许除了黑名单之外的所有输入,是不安全的,因为还有许多未知的不安全事物。原文链接应用安全 XSS (Cross-site scripting) XSS,跨站脚本攻击。 SQL注入(SQL injection) 在接受不确定输入内容(如第三方站...

    baukh789 评论0 收藏0
  • 【JS基础】页面加载,性能优化,前端安全

    摘要:建议后端替换前端执行效率低,影响性能跨站请求伪造示例你已登录一个购物网站,正在浏览商品假如该网站付费接口是但是没有任何验证然后你收到一封邮件,隐藏着你查看邮件的时候,就已经悄悄的付费购买了解决办法增加验证流程,如验证指纹输入密码短信验证码 页面加载 加载资源的形式 1.输入url或跳转页面加载html2.加载html中的静态资源 加载一个资源的过程 1.浏览器根据DNS服务器得到域名的...

    harriszh 评论0 收藏0

发表评论

0条评论

leone

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<