XSS 前端防火墙 —— 天衣无缝的防护
到目前为止,我们防护的深度已经差不多,但广度还有所欠缺。
例如,我们的属性钩子只考虑了 setAttribute,却忽视还有类似的 setAttributeNode。尽管从来不用这方法,但并不意味人家不能使用。
例如,创建元素通常都是 createElement,事实上 createElementNS 同样也可以。甚至还可以利用现成的元素 cloneNode,也能达到目的。因此,这些都是边缘方法都是值得考虑的。
下面我们对之前讨论过的监控点,进行逐一审核。
内联事件执行 eval
在第一篇文章结尾谈到,在执行回调的时候,最好能监控 eval,setTimeout('...') 这些能够解析代码的函数,以防止执行储存在其他地方的 XSS 代码。
先来列举下这类函数:
eval
setTimeout(String) / setInterval(String)
Function
execScript / setImmediate(String)
事实上,利用上一篇的钩子技术,完全可以把它们都监控起来。但现实并没有我们想象的那样简单。
Function 重写有意义吗
Function 是一个全局变量,重写 window.Function 理论上完全可行吧。
var raw_fn = window.Function;window.Function = function() { alert('调用Function'); return raw_fn.apply(this, arguments); }; var add = Function('a', 'b', 'return a+b'); console.log( add(1, 2) );
重写确实可行。但现实却是不堪一击的:因为所有函数都是 Function 类的实例,所以访问任何一个函数的 constructor 即可得到原始的 Function。
例如 alert.constructor,就可以绕过我们的钩子。甚至可以用匿名函数:
(function(){}).constructor
所以,Function 是永远钩不住的。
额外的执行方法
就算不用这类函数,仍有相当多的办法执行字符串,例如:
创建脚本,innerHTML = 代码
创建脚本,路径 = data:代码
创建框架,路径 = javascript:代码
......
看来,想完全把类似 eval 的行为监控起来,是不现实的。不过作为预警,我们只监控 eval,setTimeout/Interval 也就足够了。
可疑模块拦截
第二篇谈了站外模块的拦截。之所以称之『模块』而不是『脚本』,并非只有脚本元素才具备执行能力。框架页、插件都是可以运行代码的。
可执行元素
我们列举下,能执行远程模块的元素:
- 脚本
<script src="..." />
- 框架
<iframe src="..."> <frame src="...">
- 插件(Flash)
<embed src="..."> <object data="..."> <object><param name="moive|src" value="..."></object>
- 插件(其他)
<applet codebase="...">
这些元素的路径属性,都应该作为排查的对象。
不过,有这么个元素的存在,可能导致我们的路径检测失效,它就是:
<base href="...">
它能重定义页面的相对路径,显然是不容忽视的。
事实上,除了使用元素来执行站外模块,还可以使用网络通信,获得站外的脚本代码,然后再调用 eval 执行:
AJAX
目前主流浏览器都支持跨域请求,只要服务端允许就可以。因此,我们需监控 XMLHttpRequest::open 方法。如果请求的是站外地址,就得做策略匹配。不通过则放弃向上调用,或者抛出一个异常,或者给 XHR 产生一个 400 状态。
WebSocket
WebSocket 和 XHR 类似,也能通过钩子的方法进行监控。
不过,值得注意的是,WebSocket 并非是个函数,而是一个类。因此,在返回实例的时候,别忘了将 constructor 改成自己的钩子,否则就会泄露原始接口:
var raw_class = window.WebSocket;window.WebSocket = function WebSocket(url, arg) { alert('WebSocket 请求:' + url); var ins = new raw_class(url, arg); // 切记 ins.constructor = WebSocket; return ins; }; var ws = new WebSocket('ws://127.0.0.1:1000');
另外,因为它是一个类,所以不要忽略了静态方法或属性:
WebSocket.CONNECTING
WebSocket.OPEN
...
因此,还需将它们拷贝到钩子上。
框架页消息
HTML5 赋予了框架页跨域通信的能力。如果没有为框架元素建立白名单的话,攻击者可以嵌入自己的框架页面,然后将 XSS 代码 postMessage 给主页面,通过 eval 执行。
不过为了安全考虑,HTML5 在消息事件里保存了来源地址,以识别消息是哪个页面发出的。
因为是个事件,我们可以使用第一篇文章里提到的方法,对其进行捕获。每当有消息收到时,可以根据策略,决定是否阻止该事件的传递。
// 我们的防御系统
(function() {window.addEventListener('message', function(e) { if (confirm('发现来自[' + e.origin + ']的消息:\n\n' + e.data + '\n\n是否拦截?')) { e.stopImmediatePropagation(); } }, true); })(); window.addEventListener('message', function(e) { alert('收到:' + e.data) }) postMessage('hello', '*');
Run
当然,如果配置了框架页的白名单,就能完全避免这回事了。所以这项防御可以选择性的开启。
事件源
HTML5 新增了一个叫 EventSource 的接口。不过其用法与 WebSocket 非常相似,因此可以使用类似的钩子进行防御。
到此,我们列举了各种能执行远程模块的方式。事实上,对其防御并不难,难的是收集这些监控点,做到滴水不漏。
API 钩子
对于动态创建的可执行模块,我们通过属性钩子,来监控其远程路径。
创建元素的方法
这一节是针对 Chrome 的,因为它不支持原生访问器。
createElement / createElementNS 无中生有
cloneNode 克隆现有
innerHTML / outerHTML 工厂创建
前两种,通过钩子程序很容易实现。
第三种,因为 inner/outerHTML 是元素的 property,而非 attribute。由于 Chrome 是无法获取原生访问器的,所以使用钩子会导致无法调用上级接口。
再者,inner/outerHTML 传进来的是字符串。标签和属性鱼龙混杂,解析字符串肯定是不靠谱的。所以还得先调用原生 innerHTML 批量构建出节点,然后再扫描其中的元素。而这个过程中,节点挂载事件已经触发了。
所以,无需考虑第三种情况。
你可能会有疑问,既然用节点挂载事件都能搞定,为什么还要前面的钩子?其实,在第二篇文章 里已经详细讨论了,动态创建的脚本没法被事件拦截,所以才用钩子。
而通过 innerHTML 产生的脚本,是不会执行的!这个大家都听说过吧。
修改属性的访问器
通过原型链的访问器钩子,可以直接监控特定元素的特定 property,完全不影响他人,所以效率非常高。刚才列举了可以执行远程模块的元素,这些元素的路径属性,都得进行重写访问器。
当然 Chrome 可以忽略这节。
修改属性的方法
开头也提到了,除了 setAttribute 外,使用 setAttributeNode 也能设置属性,甚至还有 setAttributeNS 版本的。
由于 setAttribute 是个经常调用的方法,因此钩子程序必须做足够的优化,将额外的检测消耗降到最低。
新页面环境
除了使用最简单的框架,其实还有其他可以获得新页面的途径。
弹窗
通过弹窗也能获得新页面环境,大家都知道。但是窗口关闭,也随之销毁了,难道还能使用吗?不妨测试一下:
<style>.aa { color:red }</style> <button id="btn">POPUP</button> <script>btn.onclick = function() { var win = window.open(); var raw_fn = win.Element.prototype.setAttribute; win.close(); setTimeout(function() { console.log(raw_fn); raw_fn.call(btn, 'class', 'aa'); }, 1000); }; </script>
Run
尽管会有瞬间的闪动,但从新窗口里获取的变量确实被保留下来了,并且依然起作用。因为我们引用着它,所以即使窗口关闭,仍然不会对其内存回收的。
现实中,可以把点击事件绑在 document 上,这样用户随便点哪里都能触发,以此获得纯净的环境。
因此,我们还得把弹窗函数,也通过钩子保护起来。
除了最常用的 window.open,其实还有:
showModalDialog
showModelessDialog
opener
如果当前网页是从其他页面点击打开的,无论是弹窗还是超链接,window.opener 都记录着来源页的环境。
如果是来源页和自己又是同源站点,甚至还能访问到来源页里面的变量。
这种情况相当常见。例如从帖子列表页,点开一个帖子详情页,那么详情页是完全可以操控列表页的。
要解决这个问题也不难,直接给 window.opener 注入防护程序不就可以了,就像对待新出现的框架页那样。
但是,window.opener 可能也有自己的 opener,一层层递归上去或许有很多。每个页面也许又有自己的框架页,因此防护 window.opener 可能会执行非常多的代码。如果在初始化时就进行,或许会有性能问题。
事实上,这个冷门的属性几乎不怎么用到。所以不如做个延时策略:只有第一次访问 opener 的时候,才对其进行防护。
我们将 window.opener 进行重写,把它变成一个 getter 访问器:
var raw_opener = window.opener;
var scanned;window.__defineGetter__('opener', function() { if (!scanned) { installHook(raw_opener); scanned = true; } return raw_opener; });
这样,只要不访问 opener,就不会触发对它的防护,做到真正按需执行。
后记
关于防护监控点,也没有一个完整的答案,能想到多少算多少,以后可以慢慢补充。
但是,装了那么多的钩子及事件,对页面的性能影响有多大呢?
所以,我们还得开发一个测试控制台,来跟踪这套系统。看看监控全开时,会对页面产生多大影响。
转载于:https://www.cnblogs.com/sunshq/p/4028884.html
XSS 前端防火墙 —— 天衣无缝的防护相关推荐
- XSS 前端防火墙 —— 无懈可击的钩子
昨天尝试了一系列的可疑模块拦截试验,尽管最终的方案还存在着一些兼容性问题,但大体思路已经明确了: 静态模块:使用 MutationObserver 扫描. 动态模块:通过 API 钩子来拦截路径属性. ...
- 安全狗技术分享|Web应用防火墙之攻击防护
一旦我们正式把web应用上线后,web应用就暴露在公网的环境中,随之则会产生访问和流量,我们最常开放的80端口和443端口就有可能被探测到随之就有可能被自动化工具扫描甚至被监控和攻击,那么怎么防护这些 ...
- web漏洞扫描器原理_web应用防火墙对于网站防护有多重要!
大型的Web应用易受多种攻击,如SQL注入和跨站脚本攻击漏洞,由此可以造成宕机时间.效率降低.数据失窃.违规罚款.品牌受损.服务中断.客户不满等.为保护Web应用程序,建议企业利用Web应用防火墙. ...
- 防火墙/入侵防护系统IPS
不断增加和黑客攻击数据的不断提高,使得传统的防火墙或入侵检测技术无法满足现代网络安全的需要,而入侵防护技术的产生正是适应了这种要求. 防火墙是实施访问控制策略的系统,对流经的网络流量进行检查,拦截不符 ...
- 什么是网桥?何为网桥?防火墙的端口防护是指什么?
网桥:网桥(Bridge)像一个聪明的中继器.中继器从一个网络电缆里接收信号, 放大它们,将其送入 下一个电缆.相比较而言,网桥对从关卡上传下来的信息更敏锐一些.网桥是一种对帧进行转发的技 术,根据M ...
- 防火墙和入侵防护IPS
防火墙的必要性 驻地网:由用户终端至网络接口所包含的机线设备组成,以使用户可以灵活方便地进入接入网. 防火墙设置在驻地网和Internet之间,以建立二者之间的可控链路,构筑外部安全壁垒或者说安全边界 ...
- xss绕过php,php云人才系统多处Xss漏洞(绕过360防护)
### 简要描述: php云人才系统多处Xss漏洞(绕过360),可影响后台及其他用户. 360防护挂掉了,这该怎么办.. ### 详细说明: 虽然php云人才系统里加入360防注入脚本,对于一般的x ...
- 什么是防火墙?如何防护CC攻击?
随着互联网的不断发展,网络安全问题越来越受到人们的关注.在2018年全球风险报告中,网络安全问题排名前三,仅次于自然灾害与极端天气事件,这足以说明网络安全的重要性,而防火墙则是网络安全防护的必备产品. ...
- linux查询安装包的所有依赖包,linux:apt-get 如何安装,查询,解除依赖包
apt-cache search package 搜索包 apt-cache show package 获取包的相关信息,如说明.大小.版本等 sudo apt-get install package ...
最新文章
- 解决eclipse中java项目导出成jar包后读写UTF-8文件中文乱码问题
- [我的1024开源程序]100元写的软件工程和VB试题
- angular-js资料收集
- vux 修改 设置 主题 颜色
- javase 的一些基础常用类
- 主机管理+堡垒机系统开发:前端批量命令结果(十二)
- sqlserver 当月、 时间_sqlserver 获取时间年月日时分秒
- 调研AutoGluon数据处理与Tabular-NN
- 广数系统加工中心编程_数控加工中心编程师傅亲述:提升编程水平的建议
- processson的文件数量已达到上限如何删除老文件新建新的文件创建流程图
- 线行代数的本质-通俗易懂的讲解
- 小程序 选择地区(地区选择器)
- CSS设置输入框默认文字颜色(webkit-input-placeholder等)
- 一位卖家对淘宝查杀虚假交易痛讼!
- 阻容感基础06:电容器分类(1)-陶瓷电容
- 视图的作用是什么?有哪些好处?(面试题)
- java向文件写数据的3种方式
- ROS MoveIT2(humble)安装总结
- 安装SQL Server2008的示例数据库AdventureWorks 2008
- 博途plc连接电脑_S7-1200PLC以太网连接电脑
热门文章
- windows命令行安装python3_Python3---windows安装与运行
- Verilog功能模块——降采样
- 计算机视觉与深度学习 | 粒子群算法与遗传算法(GA)及与蚁群算法(ACO)比较
- Matlab | 数字信号处理:双线性变换法设计IIR数字滤波器
- 在串口通信开发中实现自动查找串口端口的方法
- java applet退出功能_java-如何使用内置在applet中的Button在浏览器中停止applet?
- 乒乓球比赛赛程_国乒今年最后一站比赛延期!赛程缩短比赛地温暖,教练组考察队员...
- 交通银行签约第四范式,建设全行级统一AI能力平台
- 我的世界minecraft-Python3.9编程(2)-开发环境配置(2)
- access开发精要(8)-设置行高、列宽、隐藏字段,取消隐藏字段,冻结列,取消冻结列,网格线