Lets say I have the following route to display a specific user in an API point, that is protected via some authentication middle:
Route::get('/v1/user/{user}', 'Api\V1\UserController@show')->middleware('can:show,user');
Assume my database is filled with just a handfull records. Then, going to the route without a credential:
/api/v1/user/1
will give me403 UNAUTHORIZED
/api/v1/user/999999
will give me404 NOT FOUND
In this setup, any visitor can find out how many users I have, by just poking around and trying some routes. Moreover, they can also find out the primary identifier (the id) of these users. This is something I would like to hide from a business perspective, but also from a security perspective.
An appoach that partially addresses this issue, is using UUID's. UUIDs are universally unique alpha-numeric identifiers that are 36 characters long, and Laravel supports the use of these on your models. This will hide the amount of records our have, and make it hard to find existing records. However, since it is still statistically possible to find records by just brute forcing, I feel this is not the correct answer to this problem.
So, how can I prevent a Laravel security leak where API returns not found when you are not authenticated?
CodePudding user response:
you can use this package to generate a slug. Then you can use the slug instead of the id.
https://github.com/spatie/laravel-sluggable
CodePudding user response:
You can follow GitHub's technique and return a 404
(Not found) instead of 403
(Unauthorized).
This way, attackers don't know if the resource actually exists or not.
To achieve this in Laravel, you may do it like this:
In app/Exceptions/Handler.php
, create/edit the method called render()
and check if the status code is 403
. If so, throw a 404
instead.
public function render($request, Throwable $e)
{
if ($e->getStatusCode() === 403) {
abort(404);
}
return parent::render($request, $e);
}
If you want to test it, just add this test route in routes/web.php
:
Route::get('/test', function () {
return abort(403); // should return a 404
});
Resources: