CakePHP & PHP 2006/12/15 17:45

CakePHPでCSRF対策

CakePHPでCSRF対策を行う方法です。

フレームワークに含まれているSecurityコンポーネントを使います。

Security#requestAuth()にアクションを記述しておくと、アクション実行前に正規リクエストかどうかをチェックします。チェックの方法はCSRF対策で一般的なワンタイムトークン方式です。

まずController#beforeFilter()にてチェックを行うアクションを指定します。

[app/controller/test_controller.php]

PHP:
  1. <?php
  2. class TestController extends AppController {
  3.   var $name = 'Test';
  4.   var $components = array('Security');
  5.  
  6.   function beforeFilter() {
  7.     $this->Security->requireAuth('add', 'edit');
  8.   }
  9.  
  10.   function add() {
  11.    //
  12.   }
  13.  
  14.   function edit() {
  15.    //
  16.   }
  17. }
  18. ?>

あとはビューファイルにトークンを埋め込みます。ポイントはformタグをHTMLで書かずにHtmlHelper#formTag()で記述するという事です。そうしておけばフレームワークがトークンをhiddenで埋め込んでくれます。(もとからformTag()で記述されている場合はそのままで良いです。)

[app/views/test/add.thtml]

PHP:
  1. <?php echo $html->formTag() ?>

実行時のHTMLソースは以下のような感じになります。(トークンの値は表示毎に変化します。)

HTML:
  1. <form action="/test/add/" method="post">
  2. <input type="hidden" name="data[_Token][key]" value="cfa714174ecc102178c6c540b04fa94dc0d5bd5d" id="_TokenKey" />
  3. </form>

トークンが一致しないリクエストが発生した場合は[HTTP/1.0 404 Not Found]が出力されます。(この動作は変更できます。)

上記は一つのコントローラでチェックを行っていますが、全てのフォームで同様のチェックを行うならSecurity#requestAuth()をAppController#beforeFileter()に書いておけばokです。

[app/app_controller.php]

PHP:
  1. <?php
  2. class AppController extends Controller {
  3.   var $components = array('Security');
  4.  
  5.   function beforeFilter() {
  6.     $this->Security->requireAuth('add', 'edit');
  7.   }
  8. }
  9. ?>

こうしておけば全てのControllerでadd/editアクションを実行する前にチェックがかかります。

 

ワンタイムトークン方式ではコントローラ/モデル側とビュー側の双方に記述が必要なのですが、フレームワーク側で考慮されているので手軽に使用できます。

ただ残念ながらbakeで生成したビューファイルはformタグがHTMLで書かれており、いちいち上記のように書き換える必要があります。HtmlHelperはデフォルトで読み込まれるのでformTag()で書いておいてくれれば楽なのですが。

# 気が向いたらTicket投げておきます。



■Related Posts

3 Responses to “CakePHPでCSRF対策”

  1. on 21 12月 2006 at 11:04 1.shun said …

    今、ためしてみたんですが、$html->formTag($html->url('/test/add/'.$html->tagValue('test/id')) というのは、単に $html->formTag() とするか、 $html->formTag('/test/add/'.$html->tagValue('test/id')) としたほうがよさそうですね。formTag() の中でも url() を呼んでるみたいです。どうでしょうか?

  2. on 21 12月 2006 at 12:28 2.shin@1x1 said …

    ですね。冗長な表現でした。
    表示ページ自身にsubmitするなら前者、違うページにsubmitするなら後者ですね。
    エントリも修正しておきました。

    ありがとうございました。:-)

  3. on 25 1月 2008 at 20:32 3.【CakePHP】CSRF対策でSecurityComponentを使う場合の注意点 | ねねとまつの小部屋 said …

    [...] Shin x blogさんCakePHPでCSRF対策 [...]

Trackback This Post | Subscribe to the comments through RSS Feed

Leave a Reply