CodeIgniter開啟CSRF保護時使用Ajax

最近在利用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

在〈CodeIgniter開啟CSRF保護時使用Ajax〉中有 2 則留言

  1. 很詳細的解說~ 謝謝!

    1. 謝謝你的鼓勵

發佈回覆給「阿銘」的留言 取消回覆

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料