CakePHPで外部からのデータ改竄を防止する

CakePHPでアプリケーションを作成する場合、注意しておかないと外部から容易にデータを改竄できるアプリケーションができあがってしまいます。この問題はCakePHPガイドブックにも書かれています。

外部からのデータ改竄を防止するには、CakePHPガイドブックの211~212ページに書かれている対策をしておく必要があります。ただし、この方法は値のチェックにempty()を使用しているため、フィールドの値として0を保存することができません。また、空文字とnullを区別したい場合にも対応できません。これらの問題にも対応できるように、ホワイトリストを基にフィルタリングするメソッドをAppModelクラスに追加してみました。

/app/app_model.php
class AppModel extends Model {
    // データのフィルタリング処理
    function filter($data = null, $whiteList = null) {
        // データがemptyの場合はdataプロパティを代入
        if (empty($data)) {
            $data = $this->data;
        }

        $_data = array();

        // ホワイトリストを基にデータを走査
        foreach ($whiteList as $model => $fields) {
            foreach ($fields as $field => $default) {
                // データが設定されていないか、emptyで0以外の場合はデフォルト値を代入
                if (!isset($data[$model][$field]) || (empty($data[$model][$field]) && $data[$model][$field] != '0')) {
                    $_data[$model][$field] = $default;
                } else {
                    $_data[$model][$field] = $data[$model][$field];
                }
            }
        }

        return $_data;
    }
}

実際に使用する場合は、コントローラからvalidates()やsave()の前にデータとホワイトリストの配列を渡して呼び出します。ホワイトリストはモデル名とフィールド名をキーにした二次元配列で、フィールド名とデフォルト値を設定しておきます。

/app/controllers/posts_controller.php
class PostsController extends AppController {
    var $name = 'Posts';



    // データを追加するためのアクションメソッド
    function add() {
        // POSTされたデータがあれば保存処理
        if (!empty($this->data)) {
            // 保存するフィールドのホワイトリスト
            $whiteList = array(
                'Post' => array(
                    'name' => null,
                    'description' => null
                )
            );

            // ホワイトリストを基にフィルタリング
            $data = $this->Post->filter($this->data, $whiteList);

            if ($this->Post->validates($data)) {
                $this->Post->save($data, false);
                $this->flash('データが追加されました。', '/posts/');
                return;
            }
        }
    }
}

ここまで書いた後に、モデルクラスにwhitelistというプロパティがあることに気づきました。情報がないのでよくわかりませんが、単にデータ改竄を防止したいだけの場合には、コントローラのアクションごとにwhitelistプロパティを設定するだけでもよいのかもしれません。

CakePHPは、まだこういう細かい部分でしっくりこないことが多いです。CodeIgniter ユーザガイド 日本語版を見る限りではCodeIgniterのほうが使いやすい気がしてきています。

コメント (2)

指摘されている通りwhitelistプロパティとsaveメソッドにwhitelist引数もあります。

やはりそうでしたか。
次回、使うときにはそちらを使ってみようと思います :)

コメントフォーム

トラックバック (0)

この記事へのトラックバックはまだありません。

この記事のトラックバックURI
http://dxd8.com/archives/7/trackback/
この記事のURI
http://dxd8.com/archives/7/