I am planning on using Laravel
in my next web project, for the backend
. Using the Laravel’s built-in functionality I will build an API
service. So my main concern now – is about the security of such service. Laravel’s API throttling middleware seems to be an easy to use solution, but it doesn’t quite have the flexibility that I need. Or at least I don’t see if it can handle my scenario or not.
Here are my questions. Hopefully someone can answer them.
is it possible to apply different throttling logic depending on whether the user is logged or not? (perform 2-3 throttle checks) Or do several different throttle checks within the same request.
Where is the history kept about IPs who are calling the API? Is it in HTTP headers or some kind of cache/memcached/redis?
If I want to ban an IP and then perform checks if it’s banned – is there a good tutorial on how to store this kind of information? How to integrate it with throttling? Schema examples or anything? A piece of advice would be good 🙂
Here is a quick example of logic that I want to implement eventually:
- route:
GET: /api/invoice/1
rules:
if IP throttling is enabled then I don't want to check whether user is logged in or not if (user is unauthorized) { throttle by IP. Throttle after 10 attempts within 1 minute if (number of times throttled within last 5 minutes = 0) { Retry-After: 1 minute } else if (number of times throttled within last 10 minutes > 1) { Retry-After: 10 minutes } else if (number of times throttled within last 30 minutes > 3) { Retry-After: 3 hours } else if (number of times throttled within last 8 hours minutes > 6) { ban IP for 1 week!!! } } else (user is authorised) { if (has permission: get_invoices) { throttle by JWT token. Throttle after 100 attempts within 1 minute if (number of times throttled within last 5 minutes = 0) { Retry-After: 5 minutes } else if (number of times throttled within last 30 minutes > 1) { ban user!!! } } else (user is logged in but doesn't have necessary permission { throttle by JWT token. Throttle after 50 attempts within 1 minute // apply logic different from user who has permission } }
for route N.r. 2, 3, 4 it can be a differnt logic whatsoever.
So I can not use just a single middleware like in this example, because it is based on a singlee parameter (be it IP, WTD, domain or other) and doesn’t incluse any of the banning logic
Route::group(['prefix' => 'api', 'middleware' => 'throttle:2,5'], function () { Route::get('invoice/{id}', function () { return $some invoice; }); });
I would like to receive some feedback on this matter. I am planning on going global 🙂
Advertisement
Answer
I got some really simple answers for you 🙂
Custom throttling logic
Laravel already provides you with a specific class (App/Providers/RouteServiceProvider
) where you can specify your custom throttling logic based on your needs. Here is an example provided by the official documentation:
use IlluminateCacheRateLimitingLimit; use IlluminateSupportFacadesRateLimiter; /** * Configure the rate limiters for the application. * * @return void */ protected function configureRateLimiting() { RateLimiter::for('global', function (Request $request) { return Limit::perMinute(1000); }); }
For more information please check the docs: Defining Rate Limiters
History for IPs
The documentation doesn’t show anything related to this, I suggest you to include the column ip
in the User model and store their current ip after logging in or registering. But if you’re referring to it so you can add it to your rate limiting logic, you can include (to the Limit
class) the method ->by($request->user()?->id ?: $request->ip());
which is the default one for the API throttling.
Banning users by IP
I suggest you to use the package made by cybercog laravel-ban which includes methods to check if a user is banned, ban by specific email, ip, etc. I’ve been using it for some apps I made and it’s really cool and easy to install and use.