├── README.md ├── test.html └── firewall.js /README.md: -------------------------------------------------------------------------------- 1 | # xss_jsfirewall 2 | * 前端xss防火墙 3 | 4 | * 整个代码的思想是EherDream大牛在14年写的5篇xss前端防火墙的文章,在我们都在用正则去防御xss的时候,他就提出在前端利用前端的特性去防御,思想是领先时代的 5 | * 博客链接(http://www.cnblogs.com/index-html/p/xss-frontend-firewall-1.html) 6 | * 代码是参考另一位写的,这位作者也是参考EherDream的思想,相当于一个优化吧,git地址(https://github.com/chokcoco/httphijack) 7 | * 不少代码是都是把EherDream的demo直接拿过来用的,所以代码都差不多的,就是细节地方的处理不同 8 | * 代码的解释很详细了 9 | ## 优势与短板 10 | * 整个写下来发现前端防御的确有它的好处,也有局限性 11 | * 因为防御方法是把前端的各种函数勾住或者监听页面变化,取出值来判断,所以这里涉及到一个脚本的好坏的问题,如何把一个正常的脚本,和一个攻击的脚本区分开 12 | * 这个貌似想辨识度很高的区分开还是很困难的,但是按照xss的目的,可以有个思路,xss的目的有两种:1.获取到某些信息(窃取cookie或者password) 2.模拟某些操作(类似蠕虫或者利用xssgetshell) 13 | * 对于第一种,可以拦截请求,这里拦截了ajax,websocket,PostMessage这三种跨域发送请求的方式,验证目的地址是否是白名单 14 | * 对于第二种,感觉还没有很好的方法区分,因为用js模拟用户操作正常的脚本也会,而攻击脚本也是模拟而已,也没有什么特别能跟正常操作区分开的地方,所以这里暂时只能用关键词黑名单匹配 15 | 16 | * 最后还有一点局限性就是虽然前端能获取到事件和脚本,但是如果攻击者利用'/"/script标签,成功的绕过了,那前端捕获到的就不准确了,比如 17 | ```markdown 18 | `` 19 | ``` 20 | * 其中xxxx为我们可控的如果攻击者利用双引号逃逸了输入" onmouseover=“javascript:alert(1); 21 | ```markdown 22 | `` 23 | ``` 24 | * 这样我们去取src中的值就是空,无法正确认为用户输入是"onmouseover=“javascript:alert(1); 虽然我们的脚本也可以拦截这种,因为拦截了事件 25 | * 所以这里最好是前后端配合起来用,后端只用转义符号" ' < > ( ) /等等就ok了 26 | * 然后繁杂的各种on事件啊,各种请求,各种动态脚本都交给前端来处理,这样可以前端后端各自发挥自己的优势 27 | -------------------------------------------------------------------------------- /test.html: -------------------------------------------------------------------------------- 1 | 2 | 恶意模块拦截测试 3 |
4 | Click Me 5 |


6 | 恶意事件拦截测试 7 |
8 | 9 |


10 | 静态脚本拦截测试 11 |
12 | 26 |


27 | 动态脚本拦截测试2 28 |
29 | 30 | 38 |


39 | 40 | 动态脚本拦截测试3 41 |
42 | 43 | 49 |


50 | 51 | 动态脚本拦截测试4 52 |
53 | 54 | 61 |


62 | 动态脚本拦截测试5 63 |
64 | 65 | 70 |


71 | 动态脚本拦截测试6 72 |
73 | 74 | 83 |


-------------------------------------------------------------------------------- /firewall.js: -------------------------------------------------------------------------------- 1 | //product by chengable www.chengable.com 2 | // 记录内联事件是否被扫描过的 hash map 3 | mCheckMap = {}, 4 | // 记录内联事件是否被扫描过的id 5 | mCheckID = 0; 6 | 7 | // 建立白名单,可以自定义自己的正则 8 | var whiteList = [ 9 | '^http://www.chengable.com/', 10 | '^http://127.0.0.1/' 11 | ]; 12 | var whiteListwebsocket = [ 13 | '^ws://www.chengable.com/', 14 | '^wss://www.chengable.com/', 15 | '^wss://127.0.0.1/', 16 | '^ws://127.0.0.1/' 17 | ]; 18 | // 建立黑名单 19 | var blackList = [ 20 | '192.168.1.0' 21 | ]; 22 | 23 | // 建立关键词黑名单,可以添加你自己的关键词,不同的标签黑名单不同,适应各种情况 24 | var wordblackliston = [ 25 | 26 | 'javascript', 27 | 'eval', 28 | 'alert', 29 | 'function', 30 | 'src=' 31 | ]; 32 | var jswordblacklist = [ 33 | 34 | 'javascript', 35 | 'eval', 36 | 'alert' 37 | ]; 38 | var wordblacklistDocumetnWrite = [ 39 | 'javascript', 40 | 'eval', 41 | 'script', 42 | 'iframe', 43 | 'alert', 44 | 'src=' 45 | ]; 46 | var wordblacklistinnerHTML = [ 47 | 'alert', 48 | 'javascript', 49 | 'eval', 50 | 'script', 51 | 'iframe' 52 | ]; 53 | 54 | //正则判断内容是否有害,可以在这里定义你自己的过滤规则 55 | function blackregmatch(wordblacklist,code) 56 | { 57 | var reglen=wordblacklist.length; 58 | for (i=0;i