Home > CakePHP > CakePHP における Mass Assignment 脆弱性対策

CakePHP における Mass Assignment 脆弱性対策

この記事の所要時間: 68

Rails 界隈で話題の Mass Assignment 脆弱性を CakePHP で防ぐ方法です。

cakephp_logo

Github に Mass Assignment 脆弱性が発見されて、Rails 界隈で話題になっています。この問題自体は目新しいものではなく、Rails 自体の問題というより、Rails アプリケーションの作り方の問題ということで、以前から作る側が注意を払う必要がありました。

この Mass Assignment 脆弱性は、Rails を手本に発展してきた CakePHP アプリケーションでも同様の問題が発生する可能性があります。知っている人には常識なのですが、まだ知らない人もいるかと思うので、CakePHPにおける対策方法を書いてみます。下記コードはCakePHP2系を想定していますが、考え方はCakePHP1系でも同じです。

Mass Assignment 脆弱性

CakePHP における Mass Assignment 脆弱性は、フォーム(多くはFormHelperで作成)からPOSTで送信された値をモデルに渡す時に発生します。

例えば、以下のようなフォームの場合、一見するとnameだけが送信されるように見えます。このフォームをブラウザで表示して入力内容を送信すれば、もちろんnameだけが送信されます。しかし、フォームというかHTTPリクエストは自在に改変できるので、nameの他にemailでもpasswordでも何でも送ることができます。

app/View/User/edit.ctp

<?php echo $this->Form->create('User'); ?>
<?php echo $this->Form->input('name'); ?>
<?php echo $this->Form->end('submit'); ?>

コントローラで見ると、edit()メソッド内で、$this->request->dataの値をそのままUser#save()に渡しています。サンプルコードなどではよくある書き方ですが、$this->request->dataに本来想定していないパラメータが含まれていても(上記フォームで言うところのname以外)、usersテーブルにカラムが存在すれば、送信された内容がそのままデータベースに保存されてしまいます。

app/Controller/UserController.php

<?php
App::uses('AppController', 'Contoller');

classs UserController extends AppController {
  public $uses = array('User');

  public function edit() {
    if (!empty($this->request->data['User'])) {
      $this->User->save($this->request->data);
    }
  }
}

これを悪用すると、本来入力フォームでは変更して欲しくないカラム(例えば管理者フラグや権限、もしかするとポイント数など)を外部から操作することが可能となります。

さらにModel#save()では、与えられた引数にプライマリーキー(多くはid)が含まれていると、その値にマッチするレコードをupdateしてしまいます。つまり新規追加フォームのつもりが、任意のレコードを変更されてしまう可能性があります。

この問題、実は意識しておかないと結構影響が大きいです。

対策1. SecurityComponent を使う

対策として、SecurityComponent を使う方法があります。SecurityComponentをコントローラの$componentsに記載しておけば、自動的にフォーム改ざんチェックが有効となるので、フォームを改ざんして任意のパラメータを送信してもエラーとなり、アクションメソッドが実行されません。

対策2. save()に渡す値を設定する

対策1でも対策にはなるのですが、本質的な問題は$this->request->dataに意図しないパラメータを含まれているのにそのまま処理してしまうことです。そこで、処理対象のパラメータのみを抽出して、save()には抽出したパラメータを渡すようにします。

下記がサンプルです。$dataに処理対象のパラメータだけをセットして、save()には$dataを渡しています。これにより意図しないパラメータが送られてきても、save()に渡されることはありません。

  public function edit() {
    if (!empty($this->request->data['User'])) {
      $data = array(
        'name' => Set::extract($this->request->data, 'User.name'),
      );
      $this->User->save($data);
    }
  }

不十分な対策 save()の第三引数に更新対象カラムを渡す

save()の第三引数に処理対象カラムを指定することで、意図しないカラムへの更新を防ぐという方法があります。

下記のようにsave()の第三引数にarray(‘name’)を指定して、nameのみを更新対象とします。この方法なら更新されるカラムはnameに限定することができます。しかし、$this->request->data[‘User’]にidが含まれていると、そのidに該当するレコードが更新されるという問題が残ります。つまり更新カラムはnameのみですが、その対象レコードは任意に指定されてしまいます。

  public function edit() {
    if (!empty($this->request->data['User'])) {
      $this->User->save($this->request->data, true, array('name'));
    }
  }

便利機能には注意を

$this->request->dataをそのままModel#save()に渡して処理する。この方法は簡単だし、スマートに見えます。しかし、上で見てきたように意識しておかないと意外な落とし穴にはまります。

このあたりは手を抜かずにきっちりと処理対象パラメータのみを抽出してsave()に渡すという方法が問題も起こりづらいし、挙動も把握しやすいと思います。意識していなかった人はご注意を。

Pocket

follow us in feedly

トラックバック:1

このエントリーのトラックバックURL
/blog/2012/03/mass_assignment_vulnerability_cakephp.html/trackback
Listed below are links to weblogs that reference
CakePHP における Mass Assignment 脆弱性対策 from Shin x blog
pingback from SwimmyStudy #5 活動報告 | スイミー 12-04-30 (月) 16:33

[…] -Mass Assignment脆弱性対応 CakePHP における Mass Assignment 脆弱性対策 – Shin x blog […]

Home > CakePHP > CakePHP における Mass Assignment 脆弱性対策

検索
フィード
メタ情報

Return to page top