弊社ではPHP開発の際のフレームワークとしてCakePHP3を採用しております。
CakePHP3は非常に柔軟でありながらセキュアな開発を行うことが可能ですが、インターネット上にあるサンプルコードなどを容易に参考にすると脆弱なアプリケーションとなることがあります。
今回はよく陥りがちでありながら影響の大きい「想定しないフィールドの変更」を紹介したいと思います。
意図しないPOSTデータの送信
例えば以下のようなテーブル構造のデータ(foods)があり、このデータを変更するフォームを作るとします。
id,name,owner_id
owner_idはこのデータの所有権を表しています。
データ変更フォームではこの中でnameのみを変更したいとします。
1 2 3 4 5 6 7 8 9 |
<?= $this->Form->create($food); ?> <table> <tr> <th>食べ物名</th> <td> <?= $this->Form->input('name') ?></td> </tr> </table> <?= $this->Form->button(__("変更する")); ?> <?= $this->Form->end() ?> |
1 2 3 |
$data = $this->request->data; $entity = $this->patchEntity($entity, $data); $this->save($entity); |
上記のコードはPOSTデータを既存データとマージし、DBに保存するというシンプルなコードです。
一見問題のなさそうなコードですが、POSTデータというのはHTMLの構造に関係なく常に改竄される可能性があると認識しなくてはいけません。
Chromeのデベロッパーツールなどを利用すれば簡単にPOSTデータを変更することができます。
例えば以下のようなフォームに改竄することができます。
1 2 3 4 5 6 7 8 9 10 |
<table> <tr> <th>食べ物名</th> <td> <?= $this->Form->input('name') ?></td> </tr> <tr> <th>食べ物を盗んじゃおう</th> <td> <?= $this->Form->input('owner_id') ?></td> </tr> </table> |
これをそのままPOSTされれば自由にfoodの所有権を変更されてしまいます。
つまり
$this->patchEntity($entity, $data);
の部分には変更できるデータを制限する仕組みは一切ないことになります。(モデル側のvalidateなどを考慮しない場合)
対処方法1:変更できるフィールドを制限する
以下のように変更可能なフィールド名を明示的に指定する方法です。
1 2 3 4 5 |
$data = $this->request->data; $entity = $this->patchEntity($entity, $data, [ 'fieldList' => ['name'] //変更可能なフィールド名の配列を渡す ]); $this->save($entity); |
これによってfieldList以外の項目は無視されます。
対処方法2:エンティティモデルで制限する
以下のようにモデルの_accessibleに一括代入で変更可能かを指定する方法です。
1 2 3 4 5 6 7 |
class Food extends Entity { protected $_accessible = [ 'name' => true, 'owner_id' => false, ]; } |
対処方法3:フォーム改ざん防止機能を利用する
SecurityComponentを利用し、ユーザーがフォームを改竄をすることを防止することができます。
参照:セキュリティ フォーム改ざん防止(cakebook)
以下のような制限をかけることができます。(マニュアルより抜粋)
- フォームに新規フィールドを追加することはできません。
- フォームからフィールドを削除することはできません。
- hidden フィールドの値を更新することはできません。
このようにフレームワークを利用する場合であっても公式マニュアル等をしっかりと確認しないと重大なセキュリティホールを作ってしまう可能性があります。
特にCakePHPの初学者の方はCakebookのセキュリティ部分を読むことをおすすめします。
エイミーではシステムの機能や最新技術だけでなくセキュリティ対策の研究にも力を入れております。
今後もお客さまが安心して利用できるシステムを開発できるよう努力してまいります。