csrf的原理攻击以及防止恶意攻击ps:对你很有帮助

csrf原理:

      我对csrf的理解为一种安全验证。CSRF跨站点请求伪造(Cross—Site Request Forgery),跟XSS攻击一样,存在巨大的危害性,你可以这样来理解:攻击者盗用了你的身份,以你的名义发送恶意请求,对服务器来说这个请求是完全合法的,就是黑客运用正常用户的身份进行操作。但是却完成了攻击者所期望的一个操作,比如以你的名义发送邮件、发消息,盗取你的账号,添加系统管理员,甚至于购买商品、虚拟货币转账等。 如下:其中Web A为存在CSRF漏洞的网站,Web B为攻击者构建的恶意网站,User C为Web A网站的合法用户。

CSRF攻击攻击原理及过程如下:

       1. 用户C打开浏览器,c为合法用户。访问受信任网站A,输入用户名和密码请求登录网站A;

       2.在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录网站A成功,可以正常发送

请求到网站A;进行用户c进行的合法操作。此时用户的cookie信息已经在A浏览器

       3. 用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;ps:b为攻击者构造的恶意网站

       4. 网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;

       5. 浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,网站b攻

 

击者向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户CCookie信息以C的权限处理

 

该请求,导致来自网站B的恶意代码被执行。

 

        6,使攻击者达到期望达到的目的。

 

现在我们来模拟一下curf的恶意攻击:这是一个不是很安全的网站,模拟了转账的系统,可以正常运行。

<?php
//pdo连接数据库方法
$dsn="mysql:dbname=stucourse;host=127.0.0.1";
//数据库的用户名
$user="root";
//数据库的密码
$password="root";
$object = new PDO($dsn,$user,$password);
$hidden=empty($_POST['hidden'])?'':$_POST['hidden'];
if(!$hidden) {
    $sql = "select * from student";
    $object->setAttribute(PDO::ATTR_ERRMODE, PDO::CASE_UPPER);
    $result = $object->query($sql);
    $result->setFetchMode(PDO::FETCH_ASSOC);
    $result_array = $result->fetchAll();
}else{
    #执行转账
    try{
        //生成PDO对象(面向对象);
        $object = new PDO($dsn,$user,$password);
        $object->beginTransaction(); // 开启一个事务
        $sql="update student set stu_balance=stu_balance-10 WHERE stu_name='小王'";
        $sql2="update student set stu_balance=stu_balance+10 WHERE stu_name='小张'";
        //PDO->exec() — 处理一条SQL语句,并返回所影响的条目数
        $result = $object->exec($sql);
        $result2 = $object->exec($sql2);
        if(($result+$result2)==2){
            $object->commit();//执行成功-》提交事务
            echo "转账成功!";
            header( "Location: pdo_rollback.php" );
        }else{
            $object->rollback(); // 执行失败,事务回滚
            throw new PDOException('操作失败');
        }

    }catch(PDOException $e){
        die ("Error!: " . $e->getMessage() . "<br/>");
    }
}
?>
<h1>转账功能</h1>
<form action="pdo_rollback.php" method="post">
    <input type="hidden" value="1" name="hidden">
    <table border="1">
        <tr>
            <td>姓名</td>
            <td>剩余金额</td>
        </tr>
        <?php foreach($result_array as $k=>$v){ ?>
            <tr>
                <td><?php echo $v['stu_name'] ?></td>
                <td><?php echo $v['stu_balance'] ?></td>
            </tr>
        <?php } ?>
        <tr>
            <td colspan="3"><input type="submit" value="执行(金额为10¥)" class="submit"></td>
        </tr>
    </table>
</form>
在浏览器中展示出来的效果是这样的:

正常用户运行,小王将给小张转账10元钱,接下来我已一个黑客的角色再模拟一个这样的网站,右击查看网页原代码:

 

 <h1>转账功能</h1>
 <form action="pdo_rollback.php" method="post">
 <input type="hidden" value="1" name="hidden">
 <table border="1">
 <tr>
 <td>姓名</td>
 <td>剩余金额</td>
 </tr>
 <tr>
 <td>小王</td>
 <td>100</td>
 </tr>
 <tr>
 <td>小张</td>
 <td>1240</td>
 </tr>
 <tr>
 <td colspan="3"><input type="submit" value="执行(金额为10¥)" class="submit"></td>
 </tr>
 </table>
 </form>
  

然后我们需要加一个js脚本,发送请求到转账系统,以下是一个攻击的代码:

 

<script src="../month6/thinkphp_3.2.3_full/Public/Admin/js/jquery-3.2.0.min.js"></script>
<h1>转账功能</h1>
<!--<form action="pdo_rollback.php" method="post">-->
    <input type="hidden" value="1" name="hidden">
    <table border="1">
        <tr>
            <td>姓名</td>
            <td>剩余金额</td>
        </tr>
        <tr>
            <td>小王</td>
            <td>-1120</td>
        </tr>
        <tr>
            <td>小张</td>
            <td>1020</td>
        </tr>
        <tr>
            <td colspan="3"><input type="submit" value="执行(金额为10¥)" class="submit"></td>
        </tr>
    </table>
<!--</form>-->

<script>

</script>
<script>
    $('.submit').on('click',function(){
        $.post({
            url:'http://localhost/month7/pdo_rollback.php',
            type:'post',
            data:{hidden:1},
            success:function(json_data){
                console.log(json_data);
            }
        })
    })
</script>

每次刷新,小王都讲自动给小张转账10元,这个转账系统遭受了恶意攻击。

那么,如何防止curf的攻击呢?

1,添加一个token请求

在这里我做了一个随机生成一个token,将token存入session(这里也可以存入数据库)并将token作为表单提交post传来的值,然后通过请求转账的时候通过token验证用户身份,判断是否为合法请求,具体改进代码如下:

 

<?php
session_start();//先匹配session
//pdo连接数据库方法
$dsn="mysql:dbname=stucourse;host=127.0.0.1";
//数据库的用户名
$user="root";
//数据库的密码
$password="root";
$object = new PDO($dsn,$user,$password);
$hidden=empty($_POST['hidden'])?'':$_POST['hidden'];
if(!$hidden) {
    $csrf_token=rand(10000,99999);
    $new_token=md5('pdo_rollback.php'.$csrf_token);
    $_SESSION['csrf_token']=$new_token;
//    print_r($_SESSION['csrf_token']);exit;
    $sql = "select * from student";
    $object->setAttribute(PDO::ATTR_ERRMODE, PDO::CASE_UPPER);
    $result = $object->query($sql);
    $result->setFetchMode(PDO::FETCH_ASSOC);
    $result_array = $result->fetchAll();
}else{
    #执行转账
        if($hidden!=$_SESSION['csrf_token']){
            echo '非法请求1!';exit;
        }else{
            try{
                //生成PDO对象(面向对象);
                $object = new PDO($dsn,$user,$password);
                $object->beginTransaction(); // 开启一个事务
                $sql="update student set stu_balance=stu_balance-10 WHERE stu_name='小王'";
                $sql2="update student set stu_balance=stu_balance+10 WHERE stu_name='小张'";
                //PDO->exec() — 处理一条SQL语句,并返回所影响的条目数
                $result = $object->exec($sql);
                $result2 = $object->exec($sql2);
                if(($result+$result2)==2){
                    $object->commit();//执行成功-》提交事务
                    echo "转账成功!";
                    header( "Location: pdo_rollback.php" );
                }else{
                    $object->rollback(); // 执行失败,事务回滚
                    throw new PDOException('操作失败');
                }

            }catch(PDOException $e){
                die ("Error!: " . $e->getMessage() . "<br/>");
            }
        }
}
?>
<h1>转账功能</h1>
<form action="pdo_rollback.php" method="post">
    <input type="text" value="<?=$new_token ?>" name="hidden">
    <table border="1">
        <tr>
            <td>姓名</td>
            <td>剩余金额</td>
        </tr>
        <?php foreach($result_array as $k=>$v){ ?>
            <tr>
                <td><?php echo $v['stu_name'] ?></td>
                <td><?php echo $v['stu_balance'] ?></td>
            </tr>
        <?php } ?>
        <tr>
            <td colspan="3"><input type="submit" value="执行(金额为10¥)" class="submit"></td>
        </tr>
    </table>
</form>
红色标记的为改进好的!

对于防止csrf攻击还有以下几种解决措施:

 

1. 尽量使用POST,限制GET

GET接口太容易被拿来做CSRF攻击,看第一个示例就知道,只要构造一个img标签,而img标签又是不能过滤的数据。接口最好限制为POST使用,GET则无效,降低攻击风险。

当然POST并不是万无一失,攻击者只要构造一个form就可以,但需要在第三方页面做,这样就增加暴露的可能性。

2. 浏览器Cookie策略

IE6、7、8、Safari会默认拦截第三方本地Cookie(Third-party Cookie)的发送。但是Firefox2、3、Opera、Chrome、Android等不会拦截,所以通过浏览器Cookie策略来防御CSRF攻击不靠谱,只能说是降低了风险。

PS:Cookie分为两种,Session Cookie(在浏览器关闭后,就会失效,保存到内存里),Third-party Cookie(即只有到了Exprie时间后才会失效的Cookie,这种Cookie会保存到本地)。

PS:另外如果网站返回HTTP头包含P3P Header,那么将允许浏览器发送第三方Cookie。

3. 加验证码

验证码,强制用户必须与应用进行交互,才能完成最终请求。在通常情况下,验证码能很好遏制CSRF攻击。但是出于用户体验考虑,网站不能给所有的操作都加上验证码。因此验证码只能作为一种辅助手段,不能作为主要解决方案。

4. Referer Check

Referer Check在Web最常见的应用就是“防止图片盗链”。同理,Referer Check也可以被用于检查请求是否来自合法的“源”(Referer值是否是指定页面,或者网站的域),如果都不是,那么就极可能是CSRF攻击。

但是因为服务器并不是什么时候都能取到Referer,所以也无法作为CSRF防御的主要手段。但是用Referer Check来监控CSRF攻击的发生,倒是一种可行的方法。

5. Anti CSRF Token

现在业界对CSRF的防御,一致的做法是使用一个Token(Anti CSRF Token)。

例子:

1. 用户访问某个表单页面。

2. 服务端生成一个Token,放在用户的Session中,或者浏览器的Cookie中。

3. 在页面表单附带上Token参数。

4. 用户提交请求后, 服务端验证表单中的Token是否与用户Session(或Cookies)中的Token一致,一致为合法请求,不是则非法请求。

这个Token的值必须是随机的,不可预测的。由于Token的存在,攻击者无法再构造一个带有合法Token的请求实施CSRF攻击。另外使用Token时应注意Token的保密性,尽量把敏感操作由GET改为POST,以form或AJAX形式提交,避免Token泄露。

注意:

CSRF的Token仅仅用于对抗CSRF攻击。当网站同时存在XSS漏洞时候,那这个方案也是空谈。所以XSS带来的问题,应该使用XSS的防御方案予以解决。

总结

CSRF攻击是攻击者利用用户的身份操作用户帐户的一种攻击方式,通常使用Anti CSRF Token来防御CSRF攻击,同时要注意Token的保密性和随机性。

有什么不对的还请各位大神指出来!

转载自:https://www.cnblogs.com/lovesong/p/5233195.html

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值