CodeIgniterでPOSTをするときのセキュリティ対策(特にAjax)について


はじめに

POSTからデータベースを操作する動作は動的サイトやWebアプリを使うときには頻出する動作だと思います。しかし、第三者がこんなコードを作れば簡単にWebを改ざんできてしまいます。これを、クロスサイトリクエストフォージェリ(CSRF) と言います。

<form action="hogehoge/delete" method="post">
<input type="hidden" name="id" value="2">
<input type="submit">
</form>

主たるPHPフレームワークにはCSRF対策があってCodeigniterでも実装されています。公式のドキュメントを見ればハッキリ書いてあるのですが、application/config/config.php ファイルの設定にある$config['csrf_protection'] をTrueをすれば、フォームヘルパーだけを使っているならそのまま対応できるのですが、私のようにAjaxを多用してると、2~3時間で済むつもりが一日潰して対策に追われて、仕事ならまだしも趣味のプログラミングなら、休みが潰れた徒労感だけが残りますので、できるだけ設計段階で気がついて対策をすることを強くお勧めします。

AjaxでCSRF対策するためのコード

フォームヘルパーなら勝手に挿入されるのですが、ajaxならかならず以下のようなコードを埋め込む必要があります。

コントローラー側
$csrf = array(
        'name' => $this->security->get_csrf_token_name(),
        'hash' => $this->security->get_csrf_hash()
);
ビュー側
<input type="hidden" id="token" name="<?=$csrf['name'];?>" value="<?=$csrf['hash'];?>" />

configでホワイトリストに入れない限り全てのPOSTが絡むajaxに上のトークンの情報を入れてやらないと基本的には動きません。設計から考えておかないと殆どマイページにPOSTが絡むajaxがあると書き換えとデバッグで大変な目に遭います。(私の場合もともと書き方が悪いので作り直したかったJSを書き替えたという事情もありましたが、なぜか動かないと堂々巡りに…。)

ajaxのコードとは普段と違ってこういう風に書いてやります。


function ajax_post(elm,flg_delete){
    var csrf_hash = $("#token").val();
    var csrf_name = $("#token").attr('name');
    var postdata = {
        id : {{profile.id}},
    };//←普通のデータのように書く
    postdata[csrf_name] = csrf_hash;//トークンを入れる

    $.ajax({
        url : elm,
        type: 'POST',
        data: postdata
    })
    .done(function(data) {
        alert('OK');
    }).fail(function(data) {
        alert('NG');
    });
});

application/config/config.php ファイルの設定について

先ほどの設定の下の所に
$config['csrf_regenerate']
というのがありますが、これはTRUEがデフォルトです。これは何かと言えば、トークンが一回使い切りという設定です。全てのPOST絡みの動作がページ変移だけならそれで問題ありませんが、Ajaxでは毎回再読込でもする設定にしないと2回目以降の動作ができなくなります。Ajaxを使うときにはOFFにすることをおすすめします。

受け手のコントローラについて

受け側のコントローラはこういう風に作ります。

public function test(){
    if ( $this->input->method(TRUE) !== 'POST' ){
        show_404();
    }

    $res = $this->input->post('request');   
        echo $res;
    }

これを参考に設計段階からやるか数カ所程度なら簡単に対策ができるはずです。

まとめ

もう二度と私のような目にあう人が居なくなるように。より安全で堅牢なWeb開発を。

参考

http://web-plusplus.net/codeigniter3-csrf/ - CodeIgniter3でCSRF対策機能をONにしたらAjaxでPOSTできなかった件