LoginSignup
4
1

More than 1 year has passed since last update.

[Laravel]バリデーションexistsの挙動

Posted at

前提

  • Windows home 10
  • Laravel 8.x
  • PHP 8.1

背景

  • Laravelでバリデーションを作っていた時の話。

  • Validatorクラスを使って以下のように書いていた。

$validator = Validator::make($request->all(), [
            'product_id' => ['required', 'exists:products,id', 'integer', 'digits_between:1,9'],
        ]);

        if ($validator->fails()) {
            return redirect()->route('...')
                ->withErrors(['error' => '不正な操作です。']);
        }
  • バリデーションルールとして初めてexistsを使用した
    • 指定したリクエスト値がDB内にあるか否かをチェックしてくれるので、結構便利

問題点

  • ただ、上記のexistsの使い方は問題があった。それは

他のバリデーションルールを通す前にDBにアクセスしてしまっている点

が問題だった

  • これにより、SQLインジェクションを引き起こしかねないプログラムを書いたことになる

具体的にどんな問題があるかというと、

  • まず前提としてexistsはDBにアクセスするため、クエリを発行する
  • そして、上記のコードだとバリデーションルールが

'required''exists:...''integer''digits_between:1,9'

の順番に適用される

  • 今回でいうと、existsでDBアクセスする際にはproduct_idintegerであり、'digits_between:1,9'でなければいけない
  • しかし、今のままでは配列でも、文字列でもDBアクセスできてしまう状態になっているのが一番の問題点

対策

  • 正しくは以下のようにexistsをルールの最後に記述しなくてはいけなかった
$validator = Validator::make($request->all(), [
            'product_id' => ['required', 'integer', 'digits_between:1,9''required', 'integer', 'digits_between:1,9', 'exists:products,id'],
        ]);
  • これにより、リクエスト内にある’product_id’

'required''integer''digits_between:1,9'

を通ったのちにexistsでクエリを発行するので、セキュリティ上安全なクエリが発行され、問題なくexistsが使えるようになります。

所見

  • existsを使うとDBの値の有無チェックをする」=「SQLを発行している」
    ということに気づけば、当初の記述はしなかったですがバリデーションとクエリ発行のつながりは基本ないことが多いので、気づけませんでした。。。

  • 自分がよく実感するのですが、フレームワークを使用しているとクエリへの意識の薄れは痛感しています。。。

  • 今回の過ちにより、クエリへの意識が再認識できた点では非常にいい機会になりました!

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1