データのサニタイジング(1) save
サニタイズ導入にあたって、久しぶりでちょっと忘れていたため、この本を読み返しました。
- 作者: GIJOE
- 出版社/メーカー: ソシム
- 発売日: 2005/11/01
- メディア: 単行本
- 購入: 32人 クリック: 340回
- この商品を含むブログ (82件) を見る
(12/11 コードにミスがありました。コードとDBへの登録状態、および残件問題を修正しました)
Sanitize::clean()で一括処理?
Sanitize::clean()は、基本的なサニタイズ処理を一括で行なえる便利な関数ですが、
デフォルトでは「強い」設定側に振ってあるため、そのまま$this->dataを一括処理すると、いろいろ不具合が生じるようです。
(CakePHP)Sanitize::clean($this->data)はバリデート使ってるときはやめた方がいい!? : old_3流プログラマのメモ書き
たとえば、バリデートでメールのチェックを定義し、Sanitize::clean($this->data) にします。
そして、「-」付のメールアドレスを入れます。
そうすると、先にサニタイジングが走るので、- が 45; となります。
そして、$Model->Save 時にバリデートで 「&」 とか 「#」 とかがチェックに引っ掛かりそこで処理が止まってしまうわけです。
前述の通り、これはSanitize::html()が、 - を変換している処理に由来すると思われます。
すると理論上、 + や () をパターンに持っている場合もダメです。
じゃあ、バリデーションを行なわない、あるいはバリデーション後〜save前のbeforeSave()メソッドでサニタイズすれば良いかというと、そうとも限りません。
数値で負の値、または - で区切るdate形式が変換されると、DBに保存する段階でint型やdate,datetime型規制でエラーになるでしょう。
適宜サニタイズ
そもそも、clean()処理のうち、何が必要か。
- ヌルバイトなど、危険なコードの削除・変換
- SQLインジェクション防止(escape())
- スクリプトなど危険タグの埋め込み防止(html())
問題は、html()の処理を全体にかけているから発生している。
html()の処理はモデル単位で必要な項目にのみ行なう、というのがやはりファイナルアンサーのようです。
ただし、html()を除いたclean()の処理は、DB問い合わせの発生する前に、必ずかけることとしました。
改修
=================================================================== --- models/user.php (revision 191) +++ models/user.php (working copy) <?php @@ -96,9 +96,44 @@ + function beforeSave($options = array()) + { + // 個々のサニタイズ(Sanitize::clean(),Sanitize::escape()以外) + if (isset($this->data['User']['name']) && $this->data['User']['name']) { + $this->data['User']['name'] = Sanitize::stripAll($this->data['User']['name']); + $this->data['User']['name'] = Sanitize::html($this->data['User']['name']); + } + return parent::beforeSave($options); + } + Index: models/app_model.php =================================================================== --- models/app_model.php (revision 191) +++ models/app_model.php (working copy) @@ -1,10 +1,20 @@ <?php + +app::import('Sanitize'); + class AppModel extends Model { var $actsAs = array( 'Cakeplus.ValidationErrorI18n', ); @@ -19,6 +29,22 @@ return true; } + function beforeSave($options = array()) + { + // サニタイズ(不正コード処理、SQLエスケープのみ) + $this->data = Sanitize::clean( + $this->data, + array( + 'encode' => false, + ) + ); + + return parent::beforeSave($options); + + }
これで、タグ、改行コードなどをサニタイズして、データを登録できました
試しに、
<i>i</i>(+-'1')
という名前で登録してみると・・・
DB
mysql> SELECT name FROM users; +-----------------------------------------------------+ | name | +-----------------------------------------------------+ | Administrator | (中略) | <i>i</i>(+-'1') | +-----------------------------------------------------+
ブラウザでusers/indexに表示すると
<i>i</i>(+-'1')'s Home
と、表示されます。
次の課題
登録まではOKでしたが、実はまだ懸念があります。
それは、編集画面と文字列検索。
続きます。