CSRF(cross-site request forgery),中文名稱:跨站請求僞造
,也被稱爲:one click attack/session riding
(很形象), 縮寫爲 CSRF/XSRF
;javascript
你能夠這麼理解CSRF
:攻擊者盜用了你的身份,以你的名義發送惡意請求
。CSRF
可以作的事情包括:php
以你的名義發送郵件html
發消息java
盜取你的帳號瀏覽器
購買商品安全
虛擬貨幣轉帳服務器
最後致使你的我的隱私泄露以及財產安全。cookie
從圖中咱們能夠看到,要完成一次CSRF
攻擊,受害者必須一次完成兩個步驟session
1.登錄受信任網站A,並在本地生成cookie
2.在不退出A的狀況下,訪問了危險網站B
函數
到這裏,你也許會說:若是我不知足以上條件的中的任何一個,就不會受到攻擊
。是的,就是這樣,可是你不能保證一下條件不會發生:
1.你不能保證你登錄了一個網站後,再也不打開一個tab 頁面並訪問另外的網站。
2.你不能保證你關閉瀏覽器後,你本地的cookie 立刻過時,你上次的會話已經結束
3.上圖中所謂的攻擊網站,多是一個存在其餘漏洞的可信任的常常被人訪問的網站。
銀行網站A,它以GET請求來完成銀行轉帳的操做,如:http://www.mybank.com/Transfe...
危險網站B,它裏面有一段HTML的代碼以下:
<img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>
首先,你登陸了銀行網站A,而後訪問危險網站B,噢,這時你會發現你的銀行帳戶少了1000塊。。。
爲何會這樣呢?
緣由是銀行網站A違反了
HTTP
規範,使用GET
請求更新資源。在訪問危險網站B的以前,你已經登陸了銀行網站A,而B中的<img>以GET的方式請求第三方資源(這裏的第三方就是指A網站了,本來這是一個合法的請求,但這裏被不法分子利用了),因此你的瀏覽器會帶上你的銀行網站A的Cookie
發出GET
請求,去獲取資源http://www.mybank.com/Transfer.php?toBankId=11&money=1000
,結果銀行網站服務器收到請求後,認爲這是一個更新資源操做(轉帳操做),因此就馬上進行轉帳操做......
爲了杜絕上面的問題,銀行決定改用POST請求完成轉帳操做。可是釣魚網站也意識到銀行應該不會那麼傻逼,也與時俱進,釣魚網站B的WEB表單以下:
<html> <head> <script type="text/javascript"> function steal() { iframe = document.frames["steal"]; iframe.document.Submit("transfer"); } </script> </head> <body onload="steal()"> <iframe name="steal" display="none"> <form method="POST" name="transfer" action="http://www.myBank.com/Transfer.php"> <input type="hidden" name="toBankId" value="11"> <input type="hidden" name="money" value="1000"> </form> </iframe> </body> </html>
若是用戶還是繼續上面的操做,很不幸,結果將會是再次不見1000塊......由於這裏危險網站B暗地裏發送了POST請求到銀行!
咱們看出來,CSRF攻擊是源於WEB的隱式身份驗證機制!WEB的身份驗證機制雖然能夠保證一個請求是來自於某個用戶的瀏覽器,但卻沒法保證該請求是用戶批准發送的!
分分鐘錢就沒了,是否是想死
CSRF 能夠從服務端和客戶端兩方面着手,固然從服務器端防範效果更好
服務端的CSRF方式方法不少樣,但總的思想都是一致的,就是在客戶端頁面增長僞隨機數
1.Cookie Hashing(全部表單都包含同一個僞隨機值)
:這多是最簡單的解決方案了,由於攻擊者不能得到第三方的Cookie(理論上),因此表單中的數據也就構造失敗
<?php //構造加密的Cookie信息 $value = 「DefenseSCRF」; setcookie(」cookie」, $value, time()+3600); ?>
在表單裏增長Hash值,以認證這確實是用戶發送的請求。
<?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值驗證
<?php if(isset($_POST['check'])) { $hash = md5($_COOKIE['cookie']); if($_POST['check'] == $hash) { doJob(); } else { //... } } else { //... } ?>
這個方法我的以爲已經能夠杜絕99%的CSRF
攻擊了,那還有1%
呢....因爲用戶的Cookie很容易因爲網站的XSS漏洞而被盜取,這就另外的1%
。通常的攻擊者看到有須要算Hash值,基本都會放棄了,某些除外,因此若是須要100%的杜絕,這個不是最好的方法。
2.One-Time Tokens(不一樣的表單包含一個不一樣的僞隨機值)
:>在實現One-Time Tokens時,須要注意一點:就是「並行會話的兼容」。若是用戶在一個站點上同時打開了兩個不一樣的表單,CSRF保護措施不該該影響到他對任何表單的提交。考慮一下若是每次表單被裝入時站點生成一個僞隨機值來覆蓋之前的僞隨機值將會發生什麼狀況:用戶只能成功地提交他最後打開的表單,由於全部其餘的表單都含有非法的僞隨機值。必須當心操做以確保CSRF保護措施不會影響選項卡式的瀏覽或者利用多個瀏覽器窗口瀏覽一個站點。
1.先是令牌生成函數(gen_token()):
<?php function gen_token() { //這裏我是貪方便,實際上單使用Rand()得出的隨機數做爲令牌,也是不安全的。 $token = md5(uniqid(rand(), true)); return $token; }
2.而後是Session令牌生成函數(gen_stoken()):
<?php function gen_stoken() { $pToken = ""; if($_SESSION[STOKEN_NAME] == $pToken){ //沒有值,賦新值 $_SESSION[STOKEN_NAME] = gen_token(); } else{ //繼續使用舊的值 } } ?>
3.WEB表單生成隱藏輸入域的函數
<?php function gen_input() { gen_stoken(); echo 「<input type=\」hidden\」 name=\」" . FTOKEN_NAME . 「\」 value=\」" . $_SESSION[STOKEN_NAME] . 「\」> 「; } ?>
4.WEB表單結構:
<?php session_start(); include(」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.服務端覈對令牌:
此處省略100字。。。。懶
就這麼多,真特麼麻煩,好累?