最近在利用CodeIgniter開發網站時,需要檢查使用者輸入的值是否有重複,為了避免使用者都輸入完資料送出表單後才去檢查,利用JQuery中的Ajax在輸入完的時候就進行檢查,但是利用Chrome Developer Tool來Debug時候,發現錯誤訊息是:
POST http://localhost/index.php/my_ajax/is_username_duplicate 500 (Internal Server Error)
最後Google後發現原來是我在之前開啟CSRF的問題。
一、什麼是CSRF
CSRF(Cross-Site Request Forgey, 跨站冒名請求)為當使用者在已登入的狀態下,被攻擊的人執行了使用者未知的操作,因為,當使用者在登入狀態下,只要不關閉瀏覽器,就會保留著Session或Cookie,網站通常都是利用檢查Session或Cookie來確認使否連線進來的使用者是否已經登入,所以攻擊者可以利用社交攻擊,傳送一個連結或操作等,使用者在未知情況下去操作,就可能會依照使用者所安排好的操作去執行,聽來聽去可能有點霧煞煞,參考網路上的一下範例解釋一下:
HTTP Request有兩種分別是POST及GET,在GET 方法可以利用網址後面帶入變數的方式,例如:
攻擊者可能利用電子郵件或者社群網站寄送一個連結給使用者
http://www.buy.com/buy.php?item=002&to=attack
這個連結可能是讓使用者買某個東西送給某人,如果使用者不經意點擊,就可能發生了,那會有人說改用POST就好了,其實不盡然,因為只要攻擊者利用JavaScript就可以執行POST 方法了
二、CSRF解決方法
參考OWASP的文件,利用同步Token方式解決,可以在執行POST及GET動作時,都去檢查隨機產生出來的Token值是否正確,像Codeigniter就是利用在form中帶入Token值,到接收值的Controller中必須檢查Token值是否一致,當然檢查步驟跟產生都是Codeigniter做好的,這個方法可以避免當受到跨站攻擊時,攻擊者不知道Token值,而沒辦法讓使用者進行未知操作。
三、Codeigniter中的CSRF Protection
在Codeigniter中的CSRF 保護可以利用設定config.php開啟,在application/config/config.php中
$config['csrf_protection'] = TRUE;
$config['csrf_token_name'] = 'aming_csrf';
$config['csrf_cookie_name'] = 'csrf_cookie_name';
$config['csrf_expire'] = 7200;
只要將$config[‘csrf_protection’]設定為TRUE即可,那表單的部分要加入Token值該如何加入呢?其實,Codeigniter都做好了,只要在View中利用form_open(),form_open()就會自己產生出隱藏欄位,所以當submit時候就會把Token 值給帶過去接收的function了。
$attr = array('class' => 'form-horizontal');
echo form_open('add_user/process', $attr);
產生出的HTML
<div style=”display:none”>
<input type=”hidden” name=”aming_csrf” value=”f3d2b8571036872e780afcf46060328a” />
</div>
四、解決Ajax與CSRF Protection
了解CSRF Protection的機制後,就可以了解Ajax POST的問題了,就是需要在Ajax 中帶入Token值
var token = $('input[name=aming_csrf]').val(); //得到aming_csrf的value
var options = {'username' : username, 'aming_csrf' : token}; //帶入token值
$.post('my_ajax/is_username_duplicate', options,
function(data) {
if(data=="FALSE") {
$('#username_fail').hide();
$('#username_ok').fadeIn();
$('#username_block').removeClass("error");
} else {
$('#username_ok').hide();
$('#username_fail').fadeIn();
$('#username_block').addClass("error");
}
}
);
我們利用$(‘input[name=aming_csrf]’).val() 得到Token 值,然後在Ajax POST中加入對應的CSRF參數名稱與值,在接收POST的function就會去驗證Token 值是否正確了。
參考資料
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF) OWASP
http://aymsystems.com/ajax-csrf-protection-codeigniter-20/ AYM Systems
發佈留言