1,csrf的攻击步奏大概是:(1)可信任的用户访问a网站。(2)此用户同时(没有退出登录的情况下)访问b网站,b网站向a网站发出一个请求。
2,csrf攻击的预防办法主要是(1)验证referer。(2)自定义header,验证header。(3)token验证。
但是以上防止csrf的方法都是有缺陷的,本文阐述用“一次性令牌”的方式防止csrf攻击,代码如下:
<?php
//生成token
function genToken(){
$hash = md5(uniqid(rand(), true));
$n = rand(1, 24);
$token = substr($hash, $n, 8);
return $token;
}
//删除已存在的session,并用重新创建token的session
function genStoken(){
$token = genToken();
destroyStoken();
//session_register('csrfToken');
$_SESSION['csrfToken'] = $token;
}
//删除已存在session
function destroyStoken(){
if(!empty($_SESSION['csrfToken'])){
unset($_SESSION['csrfToken']);
session_destroy();
}
}
//输入页面的隐藏表单(隐藏token)
function gen_input(){
genStoken();
echo "<input type='hidden' name='FTOKEN_NAME' value='".$_SESSION[csrfToken]."'>";
}
//判断token是否存在
function isStoken(){
if(!empty($_SESSION[csrfToken])){
return true;
}else{
return false;
}
}
//检查token,其中FTOKEN_NAME是生成的token,原理就是拿token值和session中存放的token比较是否相同
function token_check(){
if(isStoken($_SESSION[csrfToken])) {
if(isset($_REQUEST[FTOKEN_NAME])) {
if($_REQUEST[FTOKEN_NAME] != $_SESSION[csrfToken]) {
gen_error(1);
destroyStoken();
exit();
} else {
destroyStoken();
}
} else {
gen_error(2);
destroyStoken();
exit();
}
} else {
gen_error(3);
destroyStoken();
exit();
}
}
?>
注:伪随机数会存在一定的危险性,如果在php5.3以上版本中,若是支持openSSL扩展,可以使用openssl_random_pseudo_bytes()函数
参考网站:http://www.hanguofeng.com/archives/security/preventing-csrf/