一、CSRF概念:
CSRF(Cross-Site Request Forgery):中文名称:跨站请求伪造,也被称为:one click attack/ session riding,缩写为CSRF/XSRF。
XSS是实现CSRF的诸多途径中的一条,但绝对不是唯一的一条。一般习惯上把通过XSS来实现的CSRF称为XSRF。
CSRF是伪造请求,,冒充用户在站点正常操作。我们知道,绝大多数网站是通过COOKIE等方式辨识用户身份(包括使用服务器端Session的网站,因为Session ID也是大多保存在COOKIE里面的),再予以授权的。所以要伪造用户的正常操作,最好的方法是通过XSS活链接欺骗等途径,让用户在本机(即拥有身份COOKIE的浏览器端)发起用户所不知道的请求。
二、CSRF可以做什么
要完成一次CSRF攻击,受害者必须依次完成两个步骤:
1、登录受信任网站A,并在本地生成COOKIE。
2、在不登出A的情况下,访问危险网站B。
可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你的名义发送恶意请求。
三、CSRF漏洞现状
不能保证如下情况不会发生:
1、登录一个网站,不再打开新的一个tab页面访问另外网站;
2、不能保证关闭浏览器,本地的COOKIE就立刻过期;
3、攻击的网站,可能是一个存在漏洞的可信任的经常被人访问的网站。
四、CSRF原理
示例流程图:
示例1:
银行网站A,它以GET请求来完成银行转账的操作,如:
http://www.mybank.com/Transfer.php?toBankId=11&money=1000
危险网站B,它里面有一段html代码如下:
登录网站A,未退出,然后访问网站B,银行帐号少了钞票
原因:银行网站A违反http规范,使用GET请求更新资源。在访问危险网站B之前,你已经登录银行网站A,而B中的
以GET方式请求第三方资源(这里第三方是指银行网站,被不法分子利用了),所以你的浏览器会带上你的银行网站A的COOKIE发出get请求,去获取资源"http://www.mybank.com/Transfer.php?toBankId=11&money=1000",结果银行网站服务器收到请求后,认为这是一个更新资源操作(转账操作),所以就立刻进行转账操作
第二次改进版:
为了杜绝上面的问题,银行决定改用POST请求完成转账操作。
银行网站A的WEB表单如下:
后台处理页面Transfer.php如下:
seesion_start();
if (isset($_REQUEST['toBankId']) && isset($_REQUEST['money'])) {
buy_stocks($_REQUEST['toBankId'], $_REQUEST['money']);
}
?>
危险网站B,仍然只是包含那句话html代码
执行一次,再次没了xx块人民币,原因是$_REQUEST既能获取post请求数据,也能获取get请求数据,java获取请求数据request一样存在不能区分get和post数据问题。
第三次优化版:
经过前面惨痛的教训,银行决定把获取请求数据的方法改了,改用$_POST,只获取post请求数据,后台处理页面Transfer.php代码如下:
session_start();
if (isset($_POST['toBankId']) && isset($_POST['money'])) {
buy_stocks($_POST['toBankId'], $_POST['money']);
}
?>
危险网站B与时俱进,将img换成post方法
用户继续操作危险网站B,再一次不见xx块。
理解上面3种攻击模式,其实可以看出,CSRF攻击是源于WEB的隐式身份验证机制,WEB的身份验证机制虽然可以保证一个请求是来自于某个用户浏览器,但却无法保证该请求是用户批准发送的。
五、CSRF的防御
CSRF防御可以从服务端和客户端两方面着手,防御效果是从服务端着手效果比较好。
1、服务端进行CSRF防御
服务端的CSRF就是在客户端页面增加伪随机数。
a) COOKIE Hashing(所有表单都包含同一个伪随机值):
// 构造加密的COOKIE信息
$value = "DefenseSCRF";
setCOOKIE("COOKIE", $value, time()+3600);
?>
在表单里增加hash值,以认证这确实是用户发送的请求
$hash = md5($_COOKIE['COOKIE']);
?>
" />
然后在服务器端进行Hash值验证
if (isset($_POST['check'])) {
$hash = md5($_COOKIE['COOKIE']);
if ($_POST['check'] == $hash) {
doJob();
} else {
//...
}
} else {
// ...
}
?>
这个方法基本可以杜绝大部分csrf攻击,少量由于用户的COOKIE很容易由于网站XSS漏洞而被盗取。一般攻击者看到有需要算Hash值,基本都放弃
2、验证码
这个方案的思路是:每次的用户提交都需要用户在表单中填写一个图片上的随机字符串,这个方案貌似可以完全解决CSRF。易用性稍微差一些
3、One-Time Tokens(不同的表单包含一个不同的伪随机值)
在实现One-Time Tokens时,需要注意一点:就是“并行会话的兼容”。如果用户在一个站点同时打开两个不同的表单,CSRF保护措施不应该影响它对任何表单的提交。
a) 令牌生成函数(gen_token):
function gen_token() {
$token = md5(uniqid(rand(), true));
return $token;
}
?>
b)Session令牌生成函数(gen_stoken()):
function gen_stoken() {
$pToken = "";
if ($_SESSION[STOKEN_NAME] == $pToken) {
// 没有值,赋新值
$_SESSION[STOKEN_NAME] = gen_token();
} else {
// 继续使用旧的值
}
}
?>
c)Web表单生成隐藏输入域的函数:
function gen_input() {
gen_stoken();
echo " ";
}
?>
4)Web表单结构
session_start();
include("functions.php");
?>
5)服务端核对令牌
gen_stoken();
if ($_POST['FTOKEN_NAME'] == $_SESSION[STOKEN_NAME]) {
doJob();
} else {
//...
}
?>
转载地址:http://www.cnblogs.com/hyddd/archive/2009/04/09/1432744.html