Understanding Mass Assignment in Laravel: How fillable Protects Your Models
vimuth
Posted on September 7, 2024
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')
]);
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'
]);
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());
}
This is risky. Imagine request have this
{
"name": "Alice",
"email": "alice@example.com",
"password": "password123",
"is_admin": true,
"status": "active"
}
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'];
}
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')
]
]);
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()
-
Disable Mass Assignment Protection:
- You can use
Model::unguard()
to disable mass assignment protection for the entire application or a specific block of code.
- You can use
-
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.
- After performing the operations where mass assignment protection is not needed, you should call
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();
}
Key Points:
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.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.Re-enable Protection: Always call
Model::reguard()
after performing operations that requireunguard()
to ensure that mass assignment protection is re-enabled for the rest of your application.
Posted on September 7, 2024
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.