見出し画像

[laravel8] mass assignment

LaravelではEloquentモデルのcreateメソッドを使用してデータを保存すると、保存したモデルのインスタンスを返してくれます。

use App\Models\Flight;

$flight = Flight::create([
   'name' => 'London to Paris',
]);

しかし、この方法は『mass assignmentの脆弱性』を招くとして知られていて、データベースのテーブルのカラムが書き換えられてしまう可能性があります。

mass assginment の例

例えばUserのControllerで次のようにcreateメソッドを使用したとします。Formから受け取った値をcreateメソッドを使いデータベースに保存します。

<?php

public function create(Request $request){
   $user = User::create( $request->all() );
}

しかし、もし悪意を持ったユーザーがブラウザのdev toolなどを使い次のフィールドを埋め込んでしまったらどうなるでしょうか?

<input type="hidden" name="is_admin" value="1">

もしユーザーのテーブルにis_adminのカラムが存在していれば、このユーザーは管理者権限を手に入れ管理者ページへ侵入できるかもしれません。

このような事を防ぐためにlaravelのeloquentモデルでは$fillable$guardedのプロパティが良いされています。

fillable

$fillableプロパティはmass assginment、つまり一括でデータを挿入する時に、挿入できるカラムを定義します。

次のコードを見てみましょう。

Post.php

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
   use HasFactory;

   protected $fillable = ['title', 'excerpt', 'body'];
}

title, excerpt,bodyのカラムはmass assignmentできることを定義しました。

tinkerを使って確認してみると

$php artisan tinker
Psy Shell v0.10.8 (PHP 8.0.3 — cli) by Justin Hileman
>>> use App\Models\Post;
>>> Post::create(['title' => 'test title', 'excerpt' => 'asdfa asdf a fasdf a', 'body' => 'body body body']);
=> App\Models\Post {#4223
    title: "test title",
    excerpt: "asdfa asdf a fasdf a",
    body: "body body body",
    updated_at: "2021-05-17 11:21:30",
    created_at: "2021-05-17 11:21:30",
    id: 3,
  }
>>>

エラーもなくcreateで保存できています。

では、idを一緒に挿入できるか試してみましょう。

>>> Post::create(['id' => 1000, 'title' => 'test title2', 'excerpt' => 'asdfa2 asd2f 2a2 2fasdf a', 'body' => 'body2 body2 body2']);
=> App\Models\Post {#4279
    title: "test title2",
    excerpt: "asdfa2 asd2f 2a2 2fasdf a",
    body: "body2 body2 body2",
    updated_at: "2021-05-17 11:24:44",
    created_at: "2021-05-17 11:24:44",
    id: 4,
  }
>>> 

'id' => 1000, を追加しましたが、作成されたインスタンスのidは4になっていますね。

guarded

$guardedプロパティは$fillableの逆になります。$fillableの時はmass assignmentできるカラムを指定しましたが、$guardedはmass assignmentできないカラムを指定します。

Post.phpを次のようにidカラムをガードするように変更しました。

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
   use HasFactory;

   protected $guarded = ['id'];
}

tinkerでcreateメソッドを実行してみます。

>>> use App\Models\Post;>>> Post::create(['id' => 1000, 'title' => 'test title3', 'excerpt' => '3333333f a', 'body' => 'body3 body3 body3']);
=> App\Models\Post {#4225
    title: "test title3",
    excerpt: "3333333f a",
    body: "body3 body3 body3",
    updated_at: "2021-05-17 11:32:50",
    created_at: "2021-05-17 11:32:50",
    id: 5,
  }

idを1000で挿入を試みましたが、作成されたインスタンスではidが5になっていますね。idが守られている事がわかりました。

最後に

laravelはこのように悪意のあるユーザーから守ってくれる機能を標準で準備しています。しかし、フォームの値などを保存する時は必ずバリデーションを行い、データをコントロールすることを心がけましょう。

この記事が気に入ったらサポートをしてみませんか?