DEV Community

vimuth
vimuth

Posted on

Understanding Mass Assignment in Laravel: How fillable Protects Your Models

In Laravel, mass assignment allows you to quickly create or update records by passing an array of attributes. While convenient, it can also expose your application to security risks if not handled correctly. That’s where the fillable property comes in—it ensures that only specific fields can be mass-assigned, protecting sensitive data. This article explains how fillable works, its advantages, and why it doesn’t apply when using the save() method and how to avoid this fillable if don't need that.

What is Mass Assignment

Mass assignment refers to assigning multiple attributes to a model at once using an array. It usually happens in one of the following ways:

1. Using create():

// Creating two users using mass assignment
User::create([
    'name' => 'Alice',
    'email' => 'alice@example.com',
    'password' => bcrypt('password123')
]);

User::create([
    'name' => 'Bob',
    'email' => 'bob@example.com',
    'password' => bcrypt('secret456')
]);

Enter fullscreen mode Exit fullscreen mode

In this example, both create() calls use mass assignment to set multiple attributes at once.

2. Using update():

// Finding two users and updating their information using mass assignment
$user1 = User::find(1);
$user1->update([
    'name' => 'Alice Updated',
    'email' => 'alice_new@example.com'
]);

$user2 = User::find(2);
$user2->update([
    'name' => 'Bob Updated',
    'email' => 'bob_new@example.com'
]);

Enter fullscreen mode Exit fullscreen mode

Here, the update() method allows multiple fields to be updated at once through mass assignment.

Issues of Mass Assignment

Using mass assignment without proper controls can introduce serious security vulnerabilities. Consider the following example in your controller:

public function store(Request $request)
{
    // This allows all fields from the request to be mass-assigned
    User::create($request->all());
}
Enter fullscreen mode Exit fullscreen mode

This is risky. Imagine request have this

{
    "name": "Alice",
    "email": "alice@example.com",
    "password": "password123",
    "is_admin": true,
    "status": "active"
}
Enter fullscreen mode Exit fullscreen mode

Imagine they are adding an Admin and change everything. This can lead to unauthorized privilege escalation or unintended account modifications.

fillable Array and how it prevents this issues

To prevent mass assignment of sensitive fields like is_admin and status, you can specify which fields are allowed for mass assignment using the fillable array in the User model.

class User extends Model
{
    // Define the fields that are allowed for mass assignment
    protected $fillable = ['name', 'email', 'password'];
}
Enter fullscreen mode Exit fullscreen mode

With the fillable array defined as shown above, only the attributes listed in the array can be mass-assigned. This means that even if a request contains fields like is_admin or status, they will be ignored when using mass assignment methods like create() or update().

Notes to consider.

insert() method not considering fillables.

insert() is a query builder method, not an Eloquent model method, so it bypasses Eloquent's features like mass assignment protection, events, and model accessors/mutators.

User::insert([
    [
        'name' => 'Alice',
        'email' => 'alice@example.com',
        'password' => bcrypt('password123')
    ],
    [
        'name' => 'Bob',
        'email' => 'bob@example.com',
        'password' => bcrypt('secret456')
    ]
]);
Enter fullscreen mode Exit fullscreen mode

Ignore fillable array if needed.

If you need to bypass the fillable array for a specific operation, you can use the unguard() method provided by Laravel's Eloquent model. This method allows you to disable mass assignment protection temporarily.

How to Use unguard()

  1. Disable Mass Assignment Protection:

    • You can use Model::unguard() to disable mass assignment protection for the entire application or a specific block of code.
  2. Enable Mass Assignment Protection Again:

    • After performing the operations where mass assignment protection is not needed, you should call Model::reguard() to re-enable it.

Example Usage:

Temporarily Disable Mass Assignment Protection

use Illuminate\Database\Eloquent\Model;

public function store(Request $request)
{
    // Temporarily disable mass assignment protection
    Model::unguard();

    // Validate the request data (if needed)
    $validatedData = $request->validate([
        'name' => 'required|string|max:255',
        'email' => 'required|email|unique:users,email',
        'password' => 'required|string|min:8',
    ]);

    // Prepare data for insertion
    $userData = [
        'name' => $validatedData['name'],
        'email' => $validatedData['email'],
        'password' => bcrypt($validatedData['password']),
        'is_admin' => $request->input('is_admin'),  // Example of bypassing fillable
        'status' => $request->input('status'),      // Example of bypassing fillable
        'created_at' => now(),
        'updated_at' => now(),
    ];

    // Insert the record
    User::insert($userData);

    // Re-enable mass assignment protection
    Model::reguard();
}
Enter fullscreen mode Exit fullscreen mode

Key Points:

  1. Use with Caution: unguard() bypasses the fillable protection, so use it carefully. Ensure that you validate and sanitize the data properly before inserting it into the database.

  2. Scope of unguard(): It affects all models in the application during its scope. If you only need to bypass fillable protection for specific models or operations, it's better to handle it at the model level or within a specific code block.

  3. Re-enable Protection: Always call Model::reguard() after performing operations that require unguard() to ensure that mass assignment protection is re-enabled for the rest of your application.

Top comments (0)