CSRF的防護能夠從服務端和客戶端兩方面着手,防護效果是從服務端着手效果比較好,如今通常的CSRF防護也都在服務端進行。php
服務端的CSRF方式方法不少樣,但總的思想都是一致的,就是在客戶端頁面增長僞隨機數。html
(1).Cookie Hashing(全部表單都包含同一個僞隨機值):瀏覽器
這多是最簡單的解決方案了,由於攻擊者不能得到第三方的Cookie(理論上),因此表單中的數據也就構造失敗了:>安全
1
2
3
4
5
|
<?php
//構造加密的Cookie信息
$value = 「DefenseSCRF」;
setcookie(」cookie」, $value, time()+3600);
?>
|
在表單裏增長Hash值,以認證這確實是用戶發送的請求。服務器
1
2
3
4
5
6
7
8
9
|
<?php
$hash = md5($_COOKIE['cookie']);
?>
<form method=」POST」 action=」transfer.php」>
<input type=」text」 name=」toBankId」>
<input type=」text」 name=」money」>
<input type=」hidden」 name=」hash」 value=」<?=$hash;?>」>
<input type=」submit」 name=」submit」 value=」Submit」>
</form>
|
而後在服務器端進行Hash值驗證cookie
1
2
3
4
5
6
7
8
9
10
11
12
|
<?php
if(isset($_POST['check'])) {
$hash = md5($_COOKIE['cookie']);
if($_POST['check'] == $hash) {
doJob();
} else {
//...
}
} else {
//...
}
?>
|
這個方法我的以爲已經能夠杜絕99%的CSRF攻擊了,那還有1%呢....因爲用戶的Cookie很容易因爲網站的XSS漏洞而被盜取,這就另外的1%。通常的攻擊者看到有須要算Hash值,基本都會放棄了,某些除外,因此若是須要100%的杜絕,這個不是最好的方法。session
(2).驗證碼dom
這個方案的思路是:每次的用戶提交都須要用戶在表單中填寫一個圖片上的隨機字符串,厄....這個方案能夠徹底解決CSRF,但我的以爲在易用性方面彷佛不是太好,還有聽聞是驗證碼圖片的使用涉及了一個被稱爲MHTML的Bug,可能在某些版本的微軟IE中受影響。函數
(3).One-Time Tokens(不一樣的表單包含一個不一樣的僞隨機值)post
在實現One-Time Tokens時,須要注意一點:就是「並行會話的兼容」。若是用戶在一個站點上同時打開了兩個不一樣的表單,CSRF保護措施不該該影響到他對任何表單的提交。考慮一下若是每次表單被裝入時站點生成一個僞隨機值來覆蓋之前的僞隨機值將會發生什麼狀況:用戶只能成功地提交他最後打開的表單,由於全部其餘的表單都含有非法的僞隨機值。必須當心操做以確保CSRF保護措施不會影響選項卡式的瀏覽或者利用多個瀏覽器窗口瀏覽一個站點。
如下個人實現:
1).先是令牌生成函數(gen_token()):
1
2
3
4
5
6
7
|
<?php
function gen_token() {
//這裏我是貪方便,實際上單使用Rand()得出的隨機數做爲令牌,也是不安全的。
//這個能夠參考我寫的Findbugs筆記中的《Random object created and used only once》
$
token = md5(uniqid(rand(), true));
return $token;
}
|
2).而後是Session令牌生成函數(gen_stoken()):
1
2
3
4
5
6
7
8
9
10
11
12
|
<?php
function gen_stoken() {
$pToken = "";
if($_SESSION[STOKEN_NAME] == $pToken){
//沒有值,賦新值
$_SESSION[STOKEN_NAME] = gen_token();
}
else{
//繼續使用舊的值
}
}
?>
|
3).WEB表單生成隱藏輸入域的函數:
1
2
3
4
5
6
7
|
<?php
fu
nction gen_input() {
gen_stoken();
echo 「<input type=\」hidden\」 name=\」" . FTOKEN_NAME . 「\」
value=\」" . $_SESSION[STOKEN_NAME] . 「\」> 「;
}
?>
|
4).WEB表單結構:
1
2
3
4
5
6
7
8
9
10
|
<?php
session_start();
i
nclude(」functions.php」);
?>
<form method=」POST」 action=」transfer.php」>
<input type=」text」 name=」toBankId」>
<input type=」text」 name=」money」>
<? gen_input(); ?>
<input type=」submit」 name=」submit」 value=」Submit」>
</FORM>
|
5).服務端覈對令牌:
這個很簡單,這裏就再也不囉嗦了。
上面這個其實不徹底符合「並行會話的兼容」的規則,你們能夠在此基礎上修改。
原文:
http://www.moonsec.com/post-627.html