We are going to continue our discussion on Laravel and website security and introduce an API endpoint. I will also explore Laravel’s rate-limiting functionality. To set things in proper context, I will use the to-do app developed in the previous article.
Laravel throttle incorporates an easy-to-use, rate restricting abstraction, which, in conjunction with your application’s cache, gives an easy way to constrain any activity during an indicated window of time. Experience the dynamic efficiency of this feature amplified by top-tier Laravel hosting solutions.
Throttling something in Laravel isn’t rocket science. You usually need to limit an action based on a number of attempts inside a time window, like when the client makes an Ask. The throttle middleware does that for you, and the default LoginController automatically throttles logins.
Managed Laravel Hosting: Your Laravel Performance Boost!
Elevate Your Laravel Experience with Cloudways’ Laravel Managed Hosting – Where Expertise Meets Exceptional Performance.
What is rate limiting?
Rate-limiting is the control of the number of requests per unit time. It can be applied to ports, IPs, routes, etc. When used correctly, it can efficiently block out malicious bots. In the case of our API, it can mitigate DOS attacks, making our API accessible without downtime for legitimate users.
Note, rate limiting can also be done via a firewall. For example using IPTables on Debian based systems:
> iptables -I INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent \ --set > iptables -I INPUT -p tcp --dport 80 -i eth0 -m state --state NEW -m recent \ --update --seconds 60 --hitcount 10 -j DROP
This will limit hits to port 80, 10 times per minute. However, this approach makes it difficult, if not impossible, to only apply rate limiting to the API routes and not the entire site. Fortunately, Laravel (versions 5.2 and above) has built-in API Throttling Middleware for this exact purpose.
Read More About:Working With Middleware in Laravel
Laravel Rate Limiting
First, let’s create the API.
The idea is to be able to add a task by using an API route. This should be simple enough. We just add two routes (to list tasks and add tasks) and instead of returning a template, we return a JSON response.
Route::group(['prefix' => 'api/v1'], function () { Route::get('/getTasks', function () { return Task::all(); }); Route::post('/addTask', function (Request $request) { $validator = Validator::make($request->all(), [ 'names' => 'required|max:255', ]); if ($validator->fails()) { return response()->json(['error' => $validator->messages()], 200); } $task = new Task; $task->names = $request->names; $task->save(); return response()->json(['response' => "Added {$request->names} to tasks."], 200); }); });
Read More About:Create Rest API in Laravel With Authentication Using Passport
Now, we can use curl to add and list the tasks.
> curl -X POST -H "Content-Type: application/json" --data '{"names": "Make a cake" }' http://10.10.0.10:8880/api/v1/addTask {"response":"Added Make a cake to tasks."} > curl http://10.10.0.10:8880/api/v1/getTasks [{"id":7,"names":"Grocery shopping","created_at":"2016-05-12 06:18:46","updated_at":"2016-05-12 06:18:46"},{"id":8,"names":"Dry cleaning","created_at":"2016-05-12 06:18:52","updated_at":"2016-05-12 06:18:52"},{"id":13,"names":"Car wash","created_at":"2016-05-12 09:51:01","updated_at":"2016-05-12 09:51:01"},{"id":23,"names":"Make a cake","created_at":"2016-06-24 07:13:21","updated_at":"2016-06-24 07:13:21"}]
Task “Make a cake” has been added. Now, let’s add 10 more in quick succession…
> for i in `seq 1 10`; do curl -X POST -H "Content-Type: application/json" --data '{"names": "Make a cake" }' http://10.10.0.10:8880/api/v1/addTask; done;
This allows us to add 10 tasks within milliseconds (638 ms to be exact). Without rate limiting, this makes the app vulnerable to a very basic DOS attack.
Now let’s use the built in Laravel rate limiting which limits the actions/responses per minute. Change the API wrapper for the use of Throttling Middleware
Route::group(['prefix' => 'api', 'middleware' => 'throttle:3,10'], function () { ... });
This will cap requests made by an IP to 3 every 10 minutes. Next time the user hits the API from the same IP, the following response will be returned:
... < X-RateLimit-Limit: 3 < X-RateLimit-Remaining: 0 < Retry-After: 599 ...
Too Many Attempts.
The key to rate limiting is finding the right balance. In our sample “To-do tasks” app, if 3 tasks every ten minutes seems too restrictive, we could change it to 3 tasks per minute with the following (omitting the second number, since by default it is set to 1 minute , i.e. ‘middleware’ => ‘throttle’, will limit 10 requests per minute).
Stop Wasting Time on Servers
Cloudways handle server management for you so you can focus on creating great apps and keeping your clients happy.
Route::group(['prefix' => 'api', 'middleware' => 'throttle:3'], function () { ... });
Using fields other than IP to throttle
Many institutions and ISP’s use NAT’d solutions. Hence, it is not advisable to limit an entire group of people just because one of them is abusing the API. If we want to throttle by something unit other than IP, all we have to do is extend the base ThrottleRequests class and override the resolveRequestSignature function:
protected function resolveRequestSignature($request) { if (! $request->route()) { throw new RuntimeException('Unable to generate fingerprint. Route unavailable.'); } return sha1( implode('|', $request->route()->methods()). '|'.$request->route()->domain(). '|'.$request->route()->uri(). '|'.$request->ip() // Replace this line ); }
Replace the $request->ip() field with some other field. For example, to throttle using the session id as the unique key, add:
$request->session()
Or if you want to throttle by using the user_id passed into the request,
$request->input('user_id')
Or even the API Key
$request->header(‘API-KEY’)
The only requirement here is that the field in question be unique between users. But that’s about it. We have our API rate limiting in place.If you need further clarification or wish to share your opinion, do leave a comment below.
Read More About:Creating a REST API in Lumen
Dynamic Rate Limiting
With Laravel, you can specify the maximum number of requests based on the attribute of authenticated User’s model, using the feature of dynamic rate limiting.
Prerequisites
For the purpose of this tutorial, I assume that you have a Laravel application installed on a web server. My setup is:
- Laravel 5.5
- PHP 7.1
- MySQL
- Node.js with NPM
In my experience, server management issues could be a serious roadblock for developers. I avoid these roadblocks by opting for Cloudways. Cloudways offers a great development stack (known as ThunderStack) to host Laravel projects and takes care of all server level problems. You can try out Cloudways for free by signing for an account.
Laravel simplifies the process of limiting the number of requests a client could make for a particular action. Consider the following snippet from the Laravel Docs:
Route::middleware('auth:api', 'throttle:60,1')->group(function () { Route::get('/user', function () { // }); });
In the above snippet, the authenticated user can only hit the mentioned routes 60 times (and more!). This is handled by the throttle middleware. While this is great in some cases, this is not enough in most. Usually, dynamic rate limiting is an essential requirement of the project.
Here is another case from the Laravel Docs:
Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () { Route::get('/user', function () { // }); });
In the above snippet, the middleware is used once again. But the request is not defined there. Rather, the attribute name is passed. In the context of the snippet, rate_limit is a field in the user’s table that records the number of requests as an integer. Using this process, developers could easily define and control the number of requests for individual users. A popular used case that comes to mind is limiting access to particular resources based on the user-opted subscription plans.
Enable/Disable Rate Limiting:
The API rate limiting middleware is enabled and applied to all the Container Endpoints by default. To disable it, set API_RATE_LIMIT_ENABLED to false in the .env file.
Laravel Throttle Package
Created by Graham Campbell, Laravel Throttle is an exclusively built package that performs rate limiting in Laravel. It requires a PHP 7.x version for its proper functioning and supports optional configuration. To start working, you need to publish all vendor assets by executing the PHP artisan command which will create the throttle.php file inside your app.
Unlock Laravel’s Potential with Cloudways’ Laravel Hosting
Laravel Hosting Taken to the Next Level – Cloudways’ Managed Hosting Offers Unbeatable Speed and Reliability.
Conclusion
Rate limiting is an important option that completely changes the project structure (for the better). Developers could easily set up and control the frequency of access to resources through a simple in-code process. Let me know if you need further clarification about Laravel rate limiting.
Laravel utilizes throttle middleware to limit the amount of traffic for a given route or gather of routes. The throttle middleware accepts two parameters that decide the maximum number of requests that can be made in a given number of minutes
Q) What is throttle in Laravel?
A) Throttle in Laravel refers to the feature that limits the number of requests a user can make to your application within a specified timeframe. It is often used to prevent abuse, such as spamming or DDoS attacks, by enforcing rate limiting.
What is the difference between throttle and rate limit?
A) Throttle is the mechanism used to control request flow, while rate limit is the specific limit (e.g., 10 requests per minute) enforced on users. Throttling implements the rate limit to manage traffic effectively.
How to fix error 429 Too Many Requests in Laravel 8?
A) You can fix error 429 error by using these different methods
Adjust Throttle Limits
- Modify rate limits in api.php or web.php to allow more requests.
- Use the RateLimiter class for precise rate-limiting logic.
Implement User Authentication
- Apply separate rate limits for authenticated and unauthenticated users to ensure fair usage.
Optimize Request Handling
- Reduce redundant requests by caching frequently accessed data.
- Use pagination or load balancing to manage heavy traffic
How to make Laravel load fast?
A) You can make your Laravel application load faster by:
Optimize Caching
- Use built-in caching for routes, views, and configuration files.
- Implement query caching to reduce database load.
- Database Optimization
Use eager loading to minimize unnecessary queries.
- Optimize database indexes and queries for better performance.
Frontend Enhancements
- Utilize CDNs to serve static assets like images and scripts.
- Minify and compress CSS, JS, and HTML files.
Q) How to implement the Laravel Throttle Request middleware in Laravel ?
A) Request refers to a process in which an authenticated user is allowed to hit the application maximum time. After that, the user’s session is either expired or is denied access to the application. Throttle Request could be implemented in Laravel as shown below
/** * Increment the counter for a given key for a given decay time. * * @param string $key * @param float|int $decayMinutes * @return int */ public function hit($key, $decayMinutes = 1) { $this->cache->add( $key.':timer', $this->availableAt($decayMinutes * 60), $decayMinutes ); $added = $this->cache->add($key, 0, $decayMinutes); $hits = (int) $this->cache->increment($key); if (! $added && $hits == 1) { $this->cache->put($key, 1, $decayMinutes); } return $hits; }
If you want to limit some activity by 10 hits per 5 minutes, than decay Minutes must be 5
Q. How to set up different rate limits for different paths ?
A) First edit the Kernel.php file and comment out its default line 40 so that it doesn’t conflict with each middleware group. You can also modify the middleware by including a second parameter that will define how long the waiting period would be until the next request could arrive.
Q. How to disable rate limiter in Laravel ?
A) For disabling the rate limiter in Laravel, first go to the app/Http/Kernel.php. There you will find the default throttle limit defined by Laravel for all api routes. Just comment out that code to disable it completely.
protected $middlewareGroups = [ ... 'api' => [ 'throttle:60,1', ], ];
Shahzeb Ahmed
Shahzeb is a Digital Marketer with a Software Engineering background, works as a Community Manager — PHP Community at Cloudways. He is growth ambitious and aims to learn & share information about PHP & Laravel Development through practice and experimentation. He loves to travel and explore new ideas whenever he finds time. Get in touch with him at [email protected]