您的位置:首页 > 其它

Web安全之CSRF跨站请求伪造攻击

2015-09-02 09:08 495 查看
CSRF全称Cross-Site Request Forgery,跨站请求伪造攻击。

其攻击原理是:

攻击者在用户浏览网页时,利用页面元素(例如img的src),强迫受害者的浏览器向Web应用程序发送一个改变用户信息的请求。

由于发生CSRF攻击后,攻击者是强迫用户向服务器发送请求,所以会造成用户信息被迫修改,更严重者引发蠕虫攻击。

CSRF攻击可以从站外站内发起。

站内发起CSRF攻击,需要利用网站本身的业务,比如“自定义头像”功能,恶意用户指定自己的头像URL是一个修改用户信息的链接,当其他已登录用户浏览恶意用户头像时,会自动向这个链接发送修改信息请求。

站外发送请求,则需要恶意用户在自己的服务器上,放一个自动提交修改个人信息的htm页面,并把页面地址发给受害者用户,受害者用户打开时,会发起一个请求。

如果恶意用户能够知道网站管理后台某项功能的URL,就可以直接攻击管理员,强迫管理员执行恶意用户定义的操作。

攻击

下面我们举个例子。

一个没有CSRF安全防御的代码如下:

$userid=$_SESSION["userid"];
$email=$_REQUEST["email"];
$tel=$_REQUEST["tel"];
$realname=$_REQUEST["realname"];
$params = array();
$params[0] =$email;
$params[1] = $tel;
$params[2] = $realname;
$params[3] =$userid;
$sql = "update user set email=?,tel=?,realname=? where userid=?";
    execUpdate($sql,$params);


代码中接收用户提交的参数“email,tel,realname”,之后修改了该用户的数据,一旦接收到一个用户发来的请求,就执行修改操作。

提交表单代码:

<form action="http://localhost/servlet/modify" method="POST">
<input name="email">
<input name="tel">
<input name="realname">
<input name="userid">
<input type="submit">
</form>


当用户点提交时,就会触发修改操作。

下面我们说说如何攻击这么一个网站。如果该网站啊alibaba.com的一个部分,那么我们可以构建两个html页面:

1. 第一个页面a.html,其中通过iframe指向b.html,把宽度和高度都设为0:

<iframe src="b.htm" width="0" height="0"></frame>


这是为了当攻击发生时,受害用户看不到提交成功结果页面。

2. 页面b.html中,有一个表单和一段脚本,脚本的作用是,当页面加载时自动提交这个表单:

<form id="modify" action="http://alibaba.com/servlet/modify" method="POST">
<input name="email">
<input name="tel">
<input name="realname">
<input name="userid">
<input type="submit">
</form>
<script>
  document.getElementById("modify").submit();
</script>


注意表单的指向是
alibaba.com/servlet/modify


3. 将a.html放在自己的web服务器上,发送给登录用户即可:




4. 用户打开a.html后,会自动提交表单,发送给alibaba.com下那个存在CSRF漏洞的Web应用,所以用户的信息,就被迫修改了。而且整个攻击过程中,受害者仅仅看到一个空白页面,且不知道自己信息已被修改。

防御

有攻击就有防御,要防御CSRF工具,必须遵循以下三步:

1. 在用户登录时,设置一个随机的TOKEN也就是令牌,同时种植在用户的cookie中,当用户浏览器关闭、或用户再次登录时,清除TOKEN:

<?php
    //构造加密的Cookie信息
    $value = “DefenseSCRF”;
    setcookie(”cookie”, $value, time()+3600);
  ?>


植入令牌到cookie中。

2. 在表单中生成一个隐藏域,它的值就是cookie中随机TOKEN:

<?php
    $hash = md5($_COOKIE['cookie']);
  ?>
  <form action="http://localhost/servlet/modify"method="POST">
      <input type=”hidden” name=”hash” value=”<?=$hash;?>”>
       <input name="email">
       <input name="tel">
       <input name="realname">
       <input name="userid">
       <input type="submit">
   </form>


通过md5加密将客户端cookie中令牌值传递到服务器端。

3. 表单被提交后,就可以判断表单中的TOKEN和用户cookie中的TOKEN是否一致,如果不一致或没有这个值,就是CSRF攻击:

<?php
        if(isset($_POST['hash'])) {
             $hash = md5($_COOKIE['cookie']);
             if($_POST['hash'] == $hash) {
                  doJob();
             } else {
        //...
             }
        } else {
      //...
        }
      ?>


以上就是防御CSRF的基本方法了。那么还有几个问题:

1. 如果表单不是post而是get方式提交呢?

如果用get方式提交,TOKEN会出现在url中,攻击者可以引诱攻击者点击自己的网站,然后从http头部中的referrer 的url来获取TOKEN,再来攻击。

2. 为什么不直接验证referrer?

网站内部也可能出现CSRF攻击,而referrer 只能判断是否来自可信任网站。

3. 如果先发生XSS攻击,攻击者可以拿到用户页面的TOKEN怎么办?

CSRF防御是建立在XSS防御之后的防御,如果XSS防御失效,攻击者可以拿到用户页面所有信息,CSRF当然会失去效果。当然我们还是可以防止这种情况的发生,就是在表单提交的时候要求输入验证码。这样就可以防御啦。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: