CakePHP

CakePHP2.1 「Securityコンポーネントの怪」を避ける

やーっぱり、ハマりました。CakePHPのSecurityコンポーネントです。

Bakeして吐き出したコードを使ってもブラックホール行きで、毎度ゴミ箱に投げ捨てられている気分です。

少し分かったのは、フォーム出力されたデータ項目と入力されたデータ項目(これPOSTでなくPUTなんです)が異なると、ブラックホール行きになる事です。

で、何が問題だったかというと、入力されたデータがフォーム出力された項目より少なくなっていた、事でした。Form->input で「parent_id」と名付けた項目が何故か option要素のないselect要素で出力されたため、data[Model][parent_id]という入力データが無かったのでした。

回避策としてビューで

$this->Form->unlockField('Model.parent_id');

を実行しておけばOKです。

2012-03-08 以下ダメポなので一旦取り消し、要再調査とします。

しかし、そう言う事で毎度煩わされることなく、もう少し能動的にチェックする方法がないか考えてみました。それが次の方法です。

フォームのトークンとセッションのトークンを比較する

フォームデータの有無でチェックに引っかかることなくCSRFを回避すると共に、Securityコンポーネントを利用する事でページバックによる再入力も避けられます。

「beforeFilter()」で「$this->Security->validatePost = false;」として、フォームデータをチェックをしないようします。ところが、これをするとCSRFのチェックもしなくなってしまうので、次のように入力のワンタイムトークンのデータと、セッションに保存されたデータが等しいかチェックするメソッドを用意します。

protected function _checkToken() {
    if (isset($this->params['_Token']['key'])) {
        if ($this->params['_Token']['key'] != $this->Session->read('_Token.key')) {
            return false;
        }
    }
    return true;
}

アクションで _checkToken()メソッドを読み出せば確認できます。

AppControllerクラスで定義して、共通利用するようにすれば楽です。

(CakePHP 2.1 RC)