Home > CakePHP | PHP > CakePHP 比較演算子インジェクションに注意

CakePHP 比較演算子インジェクションに注意

この記事の所要時間: 239

@deprecated

この情報はCakePHP1.2betaまでのものです。1.2RC1についてはこの方法は有効ではありません。詳しくはCakePHP 1.2RC1からは比較演算子をキーに書くをどうぞ。

CakePHPのモデルで検索条件を指定する場合は比較演算子に注意が必要です。

検索条件では↓な感じで条件値の他にSQLの比較演算子を入れることができます。

<?php
class UserController extends AppController {
  funtion index($id) {
     $id = is_numeric($id) ? $id : 0;
     // $id より大きなidを持つレコードを取得
     $list = $this->findAll(array('id' => '> ' . $id)); 
     $this->set('list', $list);
  }
}
?>

これを見ただけで分かる人はピンと来ますね。そう外部から送られてきた値に比較演算子が含まれていてもそれがそのままSQL文として動作してしまうわけです。

これがマズそうな場面は色々あるでしょうけど、決定的なのがログイン画面です。例としてメールアドレスとパスワードで認証するアクションを見てみます。

<?php
    function login() {
      if (!empty($this->data['User'])) {
        $conds = array();
        $conds['email'] = $this->data['User']['email'];
        $conds['password'] = $this->data['User']['password'];
        $user = $this->User->find($conds);
        if (!empty($user)) {
          // ログイン成功
        }
      }
    }
?>

まあありがちな処理だと思いますが、このアクションに[email=!=hoge@example.com&password=!=a]をPOSTすると↓のようなSQL文が発行されてしまいます。(WHERE句以降)

WHERE "email" != 'hoge@example.com' AND "password" != 'a' LIMIT 1

これだとusers.emailにhoge@expample.com、users.passwordにaのどちらもが存在しなければログインする事が可能となります。つまりユーザ情報に登録されていなさそうな値を使えば誰でもログインが可能となります。

他にも登録されているメールアドレスを入力して、パスワードだけ[!=]を使うという手もあります。これならユーザのメールアドレスさえ分かればどのユーザとしてもログインできてしまいます。

この問題の対策は2つ+1つあります。

1. findBy/findAllByを使う

findBy/findAllByを使うとこの現象は発生しません。先程のloginアクションを書き換えてみます。

<?php
//        $user = $this->User->find($conds);
      $user = $this->User->findByEmailAndPassword($conds['email']
                                                          , $conds['password']);

これなら入力された比較演算子も文字列として処理されます。

WHERE "User"."email" = '!=hoge@example.com' AND "User"."password" = '!=a' LIMIT 1

2. 入力値の前に’= ‘を付ける

findやfindAllで条件を連想配列で渡したい場合は各値の前に’= ‘を付けます。実はfindBy/findAllByでは内部的にこの処理を行ってます。つまりそれを自分でやってしまうというわけです。

ここでのポイントは’=’の後ろにスペースを入れるという事です。これが無いと一部の演算子が有効となってしまいます。

<?php
        $conds = array();
        $conds&#91;'email'&#93; = '= ' . $this->data['User']['email'];
        $conds['password'] = '= ' . $this->data['User']['password'];
        $user = $this->User->find($conds);
?>

3. 入力値を厳密にチェックする

これももちろん大事です。検索に使用する値が数値のみや日付形式といった制限がある場合はそちらのチェックでこの問題を防ぐことができます。

ただ、実は比較演算子の他に[like/ilike/in/or/not/in/between/regexp/similar to]といったキーワードも同様の問題をはらんでいます。これらは文字列の中では通常の単語として出てくる可能性もある(「Like a child」とか)ので判別が難しいです。

ちなみにこの問題が発生するのは比較演算子・キーワードが文字列の先頭になっている場合のみです。それ以外の箇所にある場合は問題ありません。

find/findAllで検索条件に連想配列を使う場合は注意を

これは忘れるとインパクトがあるのでfind/findByfindBy/findAllByで検索する場合はくれぐれもご注意を。

@see: CakePHPの何か「CakePHPのModelを使う」

Pocket

follow us in feedly

コメント (Close):2

anon 07-07-13 (金) 17:58

>このアクションに[email=!=hoge@example.com&password=!=a]をPOSTすると↓のようなSQL文が発行されてしまいます。
POSTしても、
WHERE `email` = ‘email=!=hoge@example.com&password=!=a’ AND `password` = ” LIMIT 1
このようなSQL文が発行されましたが・・・。

shinbara 07-07-13 (金) 22:36

anonさん:
こんにちは。
[email=!=hoge@example.com&password=!=a]はPOSTリクエストのメッセージボディをイメージしています。
ですのでフォームで言うとemailに[!=hoge@example.com]を、passwordに[!=a]を入力して送信した状態になります。

一度お試し下さいませ;-)

トラックバック:2

このエントリーのトラックバックURL
http://www.1x1.jp/blog/2007/07/cakephp_operator_injection.html/trackback
Listed below are links to weblogs that reference
CakePHP 比較演算子インジェクションに注意 from Shin x blog
trackback from idea*idea 07-07-03 (火) 1:52

ログイン画面のセキュリティを考える(CakePHP修行 #0…

さてさてログインフォームの改善を続けます。 次はセキュリティ関連。気になる点は以下の二つ。 ログイン画面ってわけではないですが、パスワードを平文で保存しているのが不安。 (more…)

pingback from 【CakePHP】比較演算子インジェクションをきにせず済む、findAllByやfindByでorderやlimitを指定する | ねねとまつの小部屋 07-12-26 (水) 19:28

[…] CakePHPのfindやfindAllには、Shin x blogさんのCakePHP 比較演算子インジェクションに注意やCakePHPガイドブックで言及されているとおり、条件を連想配列で渡す場合、比較演算子インジェクションに注意しなければいけません。 […]

Home > CakePHP | PHP > CakePHP 比較演算子インジェクションに注意

検索
フィード
メタ情報

Return to page top