CSRFコンポーネントについて整理【cakephp3.8】

今回は、cakephp3のCSRFコンポーネントについて勉強したので整理してまとめておきます。

CSRFコンポーネントまとめノート。

CSRFコンポーネントとは

CSRFコンポーネントとは、cakephpで簡単にしっかりとCSRF対策ができるようにするためのコンポーネントです。

コンポーネントとは、cakeアプリケーションのコントローラー部分を拡張させるための機能だというのは既にまとめていました。

では、CSRF対策とは何か簡単に整理しておきます。

CSRF対策とは

CSRF(cross site request forgery)とは、外部からフォーム送信などのリクエストを偽装してサーバーに送りつける攻撃です。クロスサイトリクエストフォージェリと呼びます。

CSRFを受けてしまうと、webサイトに不正なスクリプトやHTTPリダイレクトを埋め込むことで、ユーザーに強制的に別のサイトのプログラムを実行させてしまうといった被害が出てきます。

具体的には、意図せず個人情報を漏洩されてしまったり、ターゲットとなるサイトに妨害行為とみなされる処理を知らぬ間にさせられてしまったりします。

CSRF対策をするには

攻撃用スクリプトはなんらかの高度なプログラムかというと、そうでもなく、みなさんがよく目にするフォーム送信などで使われるクエリーパラメーターが勝手に送られてしまうというロジックです。(他のなんらかの手段でのPOST送信やPUT送信なども含む)

効果的なのは、フォームのやりとりにワンタイムパスワードをつけてあげることです。そうすることで他サイトからのリクエストを無視できます。

CSRFコンポーネントについて

では、CSRFコンポーネントについて整理していきます。

Csrfコンポーネントを読み込む

bakeコマンドで生成したらもともと入っていたりしますが、初期状態では入っていなかったりするので、Controllerのinitialiseメソッドで呼び出します。

public function initialize(){
  parent::initialize();
  $this->loadComponent('Csrf');
}

このCsrfコンポーネントをロードすると、フォームに自動的にワンタイムトークンが埋め込まれるようになります。

注意点として、フォームを作成する際はFormヘルパーを使わないと正しく生成されないようなので必ずFormヘルパーで作ります。

Csrfコンポーネントを利用する

送信側でワンタイムトークンを発行して、受け取り側でそのワンタイムトークンをチェックするという流れです。

どのようにチェックをするのかというと、送信処理の際に$_SESSIONにワンタイムトークンを保存しておいて、送信された値(hiddenでこっそりついてくる)をその$_SESSION値と比較する方法です。

送信側を作る

templateでFormヘルパーを使ってフォームを作るだけで完成です。楽だ!

<?= $this->Form->create($board) ?>
<fieldset>
    <legend><?= __('Add Board') ?></legend>
    <?php
        echo $this->Form->control('person_id', ['options' => $people]);
        echo $this->Form->control('title');
        echo $this->Form->control('content');
        echo $this->Form->control('registed', ['empty' => true]);
    ?>
</fieldset>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>

受け取り側を作る

Controllerで受け取る処理を作成すればそれだけでOKです。Csrfこんぽーねんとをロードしておけば何も記述しなくてもコンポーネントが働いてくれます。

if ($this->request->is('post')) {
    $board = $this->Boards->patchEntity($board, $this->request->getData());
    if ($this->Boards->save($board)) {
        $this->Flash->success(__('The board has been saved.'));

        return $this->redirect(['action' => 'index']);
    }
    $this->Flash->error(__('The board could not be saved. Please, try again.'));
}

Csrfコンポーネントを無効にする

一応機能としてあったので入れときます。

Csrfコンポーネントを読み込んでいると仮にFormヘルバー以外で作成したフォームなどは機能しなくなってしまいます。

そのため、特定の場合だけに対して無効にすることもできます。ただし非推奨です。

Controllerに次のメソッドを加えます。

use Cake\Event\Event;

public function beforeFilter(Event $event){
  $this->getEventManager()->off($this->Csrf);
}

以上でCsrfコンポーネントのまとめとします。