前端安全知识以及防范

作者: lotuslwb | 来源:发表于2017-05-15 16:41 被阅读205次

    基础

    XSS就是让浏览器执行想插入的js。那么如何发现这些漏洞呢?只要有输入和输出的地方都伴随着漏洞的产生,下面介绍基础的XSS漏洞分析。
    XSS攻击并非一个<sc+ript+>al+ert('xs+s漏洞')</script>(这里请看源码)语句就可以检测。

    <script>alert('xss漏洞')</script>
    
    • XSS初级测试(反射型XSS):
      反射型XSS需要欺骗用户点击才能触发XSS代码。

    • 输入框是否过滤<>’”/等字符,输入框中输入这些字符后提交,查看网页源码中这四个字符有没有被过滤;

    • 在输入框或者url的参数中输入<img onerror=alert(1) src=1>后,如果出现界面错误,那就提BUG吧;

    • 使用eval()函数,该函数执行js代码,输入框输入或者url参数等于eval("alert('Hello world')”),是否能够执行。

    • XSS中级测试:

    • 宽字节注入漏洞,GB系列这些编码格式只有两个字节,引起的安全问题是吃一个ASCII字符的现象像一个<input type=“text” value=“”> 的语句,我们要做的是闭合双引号(%22),但是如果value输入%22的话就会被转义为%5C%22,如果输入%C0%22 /><script>alert(1)</script>的话,过滤器发现%22加入转义(%5C),然而%C0吃掉了%5C,这样就闭合了前面的双引号。

    • 存储型XSS,和前面的反射型XSS不同,是将XSS代码提交服务器中并存储下来,其他人在访问能拿到该字段的页面就会触发XSS代码执行。我找到了一个乌云上淘宝宝贝详情的存储型XSS。

    • 测试建议:

    • 必须对所以交互的输入字符、http请求头部变量、cookie变量等检测字符和html关键字段;

    • 前端或者客户端做了过滤还不够,服务端也要进行过滤;

    • 为了防止存储型XSS产生,对存入数据库的字段不光要在输入字符时进行过滤和检测,还要在数据库字段输出到页面时进行过滤和检测;

    • 网上已有的XSS代码:XSS代码;

    • 乌云上很多XSS漏洞的真实例子,大家测试之余可以去搜来看看,乌云网站。

    深入

    XSS攻击的本质是执行代码,根据代码在页面中的执行环境可分为3种:

    1.存储型XSS
    用户访问正常的URL,触发代码执行。
    大部分情况是由于过滤不完全或未转码,直接渲染到页面中,导致代码执行。

    2.DOM型XSS
    用户访问正常的URL,触发代码执行。
    前端人员经常把数据埋在Dom节点中,然后通过JS代码获取内容,渲染,然后插入到页面中,导致代码被执行。

    3.反射型XSS
    用户访问经过特殊构造的URL,触发代码执行.
    常通过垃圾邮件传播,邮件内容大多是具有诱惑性的内容,引诱点击。QQ被盗后,空间说说等经常出现不明链接等等。

    存储型XSS漏洞根据代码执行位置不同,又可分为:

    1.HTML存储型

    发表文章,填写资料,留言等数据提交到后台,过滤不全,在用户访问页面的时候,恶意内容渲染到页面中,导致攻击。

    2.CSS存储型
    常见于淘宝店铺装修,网页换肤,背景图等,这些地方都需要用户提交CSS样式,甚至引入外部JS,如果对输入没有做严格的校验,直接渲染到页面,极易产生安全隐患

    淘宝商品详情页的评论记录,交易记录都曾被非法篡改。

    攻击的方式多种多样,CSS支持unicode,很多漏洞直接采用编码的方式绕过安全漏洞。

    <div style="width:expression(if(!window.x){alert(1);window.x=1})"></div>
    <link rel=stylesheet href=data:,*%7bx:expression(if(!window.x)%7balert(1);window.x=1%7d)%7d />
    <div style="width:expression(if(!window.x){alert(1);window.x=1})"></div>
    <table background="javascript:alert(/xss/)"></table>'

    3.JS存储型

    这种比较少见,有时候会前端会使用eval,jQuery.globalEval,前者在代码中比较常见,1688这边,去年安全部集中处理过一批这些漏洞。

    用户一般难以直接输入JS代码,但有时候,前端开发人员会要求将数据直接转成JS代码,放入到页面中,方便获取,如果内容未经过安全处理,攻击者就会尝试中断正常的代码逻辑,插入攻击代码。

    Dom型XSS攻击

    '''
    前端开发者,经常将数据存放在Dom节点,在某个时候,获取节点的数据,然后插入到页面中,插入到页面时,常使用jQuery('body').html('<script>alert(3)</script>') 操作,导致代码被执行。

    反射型XSS攻击

    用户访问经过特殊构造的URL,URL参数中会携带攻击代码。

    现在我们假设一种攻击场景:私信

    1. 攻击者A,利用私信功能向用户B发送私信,私信内容存在攻击代码(JS)
    2. 用户浏览私信,浏览的过程中,JS代码在同域名下,毫无顾忌地执行,相当于开发方自己的代码
    3. 用户B成为受害者
    4. 攻击代码可以将受害者B的其它私信提交到自己的内容收集平台
    5. 攻击代码自动与好友发送私信,私信内容与上述一样。从而产生新的受害者。。。。
    6. 如此循环

    可以看到,用户B的私密消息,完全被暴露。
    很多网站产品会让用户填写个人资料,身份证,姓名等等,一旦发生此类攻击,用户的信息也就被泄露了。
    目前网站依赖token做CSRF校验,其有效的前提是不存在XSS漏洞,token不会泄露。

    防御

    在编写代码的时候,尽量站在攻击者角度去编写代码。

    其实记住两点就行:

    1. 不要信任用户输入的任何数据

    2. 输入、输出过滤

    作为防御方,我们尽量够做的其实很有限,不同的场景,可能有不同的漏洞产生,提高自身的安全意识,编写安全代码是我们目前能够做的。

    举个小例子,判断一个URL是否是1688域名,在前端提交的时候会做判断,后台也会做判断。
    正则可能如下:
    /http://.*.1688.com/i
    大家可以思考一下这个正则有问题吗? 前端可能写对了,后台开发人员呢?
    在攻击发生时,往往是多个类型XSS互相利用,最后产生较大的安全问题。还有就是新技术的应用,比如NodeJs,在安全方面的处理还是不够,这种在线上也存在相同的问题。目前也有新的CSP策略,在高级浏览器(IE10,)中可以起到一定的安全防御作用,但是就当前环境来说,低版本浏览器,我们还没法放弃。
    一些例子
    2011年,新浪微博XSS蠕虫事件:攻击者利用广场的一个反射性XSS URL,自动发送微博、私信,私信内容又带有该XSS URL,导致病毒式传播。
    09年twitter也发生过类似事件。
    乌云平台也有很多此类例子,可以搜索关键词XSS

    1. 安全平台自己也有漏洞 ,rank 10,http://wooyun.org/bugs/wooyun-2010-059832
    2. 阿里云账号泄露 ,rank 20, http://wooyun.org/bugs/wooyun-2010-054102
    3. 腾讯微博 http://www.wooyun.org/bugs/wooyun-2010-020167
    4. 百度贴吧 http://www.wooyun.org/bugs/wooyun-2010-053221 太多了。。。。。。
      有时候,漏洞的危害性可能不是很大,但是极易引起用户反弹,公关问题,。

    实践 -- show me the code

    前端XSS

    前端XSS往往由于前端层面用innerHTML或者$('#id').html('...')方法时,没有对用户输入的内容和正常的HTML代码进行隔离,从而让黑客可以轻松获取JS执行权限。

    那么,标准的前端逻辑应该怎么写?

    $('#id').html('![](test.jpg)');
    

    如果我们使用的是模板,例如handbar,由于handbar默认会进行转义,因此默认即是安全的:


    理论上,我们建议能使用模板的场景尽量使用模板,能为我们节省大量的代码量,并且同时也能保证我们代码不会出现XSS漏洞。
    对于使用underscore的同学,请留意下默认的是不转义的,例如:
    hello: <%= name %>
    如果需要转义,请务必使用:
    hello: <%- name %>
    注:我们对underscore进行了改造,将这两个标识进行了翻转,经过改造后,也符合了默认转义的原则。

    成果

    在这之外,我们还有什么手段解决前端XSS问题呢?

    jQuery目前已经无孔不入,几乎找不着没有使用jQuery的业务场景。

    我们的方案是在外部对jQuery进行了hack,将所有html代码进行安全过滤,以实现前端防火墙的功能。

    过滤逻辑如下:将所有js代码过滤为无效代码, 例如:

    '''
    <img src="" onerror="alert(1)"> <script>alert(1)</script>
    '''

    会替换为:

    '''
    <img src="" onerror0="alert(1)"> <script0>alert(1)</script>
    '''

    经过此过滤,XSS就再也无法猖狂了!

    并且,此方案还有1个优点,由于此方案是全站底层进行防火部署,因此过滤算法可以随时进行优化升级,以解决今后出现新的XSS漏洞。

    不过,此方案并非没有缺陷。由于此方案屏蔽了所有的JS代码,因此对于旧逻辑中所有HTML和JS混合的场景都需要进行改造。

    但是,根据实际部署过程来看,这种混合场景占比非常非常少。

    我如何部署?

    security.js

    '''js
    (function (win) {
    var security = {}; // 初始事件正则
    var objOnEvents = {};
    var reAllEvents; // init all events
    var doc = document;
    var arrDoms = [window, doc.createElement("form")];
    try {
    arrDoms.push(doc.createElement("img"));
    arrDoms.push(doc.createElement("iframe"));
    arrDoms.push(doc.createElement("object"));
    arrDoms.push(doc.createElement("embed"));
    arrDoms.push(doc.createElement("audio"));
    } catch (e) {
    }
    var dom;
    var key;
    for (var i = 0, c = arrDoms.length; i < c; i++) {
    dom = arrDoms[i];
    for (key in dom) {
    if (/^on/.test(key)) {
    objOnEvents[key.substring(2)] = 1;
    }
    }
    }
    var arrAllEvents = [];
    for (key in objOnEvents) {
    arrAllEvents.push(key);
    }
    if (arrAllEvents.length > 0) {
    reAllEvents = new RegExp('(['"\\s\\/]on(?:' + arrAllEvents.join('|') + '))\\s*=', 'ig'); } else { reAllEvents = /(['"\s/]on(\w+))\s=/ig;
    } // HTML转义
    security.encodeHTML = function (str) {
    return String(str).replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, ''').replace(//g, '').replace(/</g, '<').replace(/>/g, '>');
    }; // 过滤html中可能引发XSS的代码
    security.htmlFilter = function (str, args) {
    var reBadTags = /<(script|link|frame)([^\w])/ig;
    var reBadAttrs = /['"\s\/](srcdoc)\s*=/ig; var reBadSrc = /[\'"\s/]src\s
    =\s['"]?\s(javascript:|data\s:\stext/html)/ig;
    str = String(str); // 过滤script & link...
    str = str.replace(reBadTags, '<$10$2'); // 过滤on事件
    str = str.replace(reAllEvents, '$10='); // 过滤srcdoc属性
    str = str.replace(reBadAttrs, ' $10='); // 过滤危险src: javascript: data:
    str = str.replace(reBadSrc, ' src0="');
    return str;
    }; // hack jQuery
    security.hookJquery = function ($) {
    if ($ && !$.fn.rawHtml) { // 1. html->rawHtml
    $.fn.rawHtml = $.fn.html;
    $.fn.html = function (value) {
    var args = Array.prototype.slice.call(arguments);
    if (typeof value === 'string' && $.htmlFilter) {
    args[0] = security.htmlFilter(value, arguments);
    }
    return $.fn.rawHtml.apply(this, args);
    };
    }
    };
    win.security = security;
    })(window);
    '''

    test.html

    ''' html
    <div id="test"></div>
    <script type="text/javascript" src="js/jquery-1.10.2.js"></script>
    <script type="text/javascript" src="security.js"></script>
    <script type="text/javascript">
    security.hookJquery($); $.htmlFilter = true; $('#test').html('<img src="" onerror="alert(1)">')
    </script>

    框架底层可以直接将jQuery进行hook,但是具体过滤逻辑是否开启取决于$.htmlFilter是否打开。

    在部署过程中,请务必要保证业务代码全部改造为纯HTML的情况下才能开启开关,否则会造成线上故障

    相关文章

      网友评论

        本文标题:前端安全知识以及防范

        本文链接:https://www.haomeiwen.com/subject/smphxxtx.html