š Looking to dive deeper into Laravel security? Check out Practical Laravel Security, my hands-on security course that uses interactive hacking challenges to teach you about how vulnerabilities work, so you can avoid them in your own code! šµļø
š When was your last security audit or penetration test? Book in a Laravel Security Audit and Penetration Test today! šµļø
If you use Laravelās Implicit Route Bindings, youāll most likely end up with a route that looks like this:
Route::get(
'/projects/{project}/plans/{plan}',
function (Project $project, Plan $plan) {
abort_unless($plan->project()->is($project), 404);
// ...
}
);
While itās easy to validate that the Plan is owned by the Project, you still need to remember to add it1 to your action, and it can look a bit ugly.
Luckily for us, Laravel has our backs (yet again). There is a handy little method in Laravelās Routing system called `scopeBindings()`
, which we can use to tell Laravel to automatically scope implicitly bound models.
Check it out:
Route::get(
'/projects/{project}/plans/{plan}',
function (Project $project, Plan $plan) {
// ...
}
)->scopeBindings();
Laravel will automatically attempt to load the āchildā binding from a relationship on the āparentā binding listed before it. In other words, in our example it will look for a matching Plan
model from the plans
relationship on the Project
model. If the child binding isnāt found, itāll throw a 404.
This is the same behaviour as our code above, but without that ugly `abort_unless()`
.
The best bit is, since itās a route method we can use it in groups too! This solves the āforgetting to add itā problem, since youāll typically group your routes and automatically add them into our scoped group.
Route::scopeBindings()
->group(function () {
Route::get('/projects/{project}/plans/{plan}', ...);
Route::get('/projects/{project}/plans/{plan}/edit', ...);
Route::get('/projects/{project}/plans/{plan}/export', ...);
// ...
});
Nice and simple, just the way we love it in Laravel!
Most all of the vulnerabilities Iāve discovered have come about because the developer forgot to include a single line of code to perform authentication, authorisation, or validation. Usually with the exact line required already written for another action in the same controller.