A "rate limiter" controls how frequently some event (e.g. an HTTP request or a login attempt) is allowed to happen. Rate limiting is commonly used as a defensive measure to protect services from excessive use.
Symfony 5.2 introduces a new RateLimiter component so you can add those protections to your own applications. For example, imagine that you want to apply the same restrictions as GitHub to your own APIs when used anonymously: 60 requests per hour and identify requests by the originating IP address.
First, configure a new rate limiter as follows:
1 2 3 4 5 6 7
# config/packages/rate_limiter.yaml
framework:
rate_limiter:
anonymous_api:
strategy: fixed_window
limit: 60
interval: '60 minutes'
Now, inject the rate limiter in your controllers or services and use it to check if the request should be allowed or not:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
// src/Controller/ApiController.php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
use Symfony\Component\RateLimiter\Limiter;
class ApiController extends AbstractController
{
// the variable name must be: "rate limiter name" + "limiter" suffix
public function index(Limiter $anonymousApiLimiter)
{
// create a limiter based on the client's IP address
// (you can also use a username/email, an API key, etc.)
$limiter = $anonymousApiLimiter->create($request->getClientIp());
// try to consume a resource; if it's accepted, serve the request
// otherwise, return a 429 (Too Many Requests) error
if (false === $limiter->consume()->isAccepted()) {
throw new TooManyRequestsHttpException();
}
// ...
}
// ...
}
That's it! The RateLimiter component implements many other features and provides two different strategies to control the limits: "fixed window" and "token bucket". Read the RateLimiter docs to learn all about its features.
It's kind of brute force protection. Can it be used with a login form?
Great post!
One thing I would like to add: Depending on the number of tools available to you, using Symfony's RateLimiter to enforce API limits/brute force production might not be the best idea. You still always get a performance penalty for starting a PHP process, booting the Symfony kernel, etc. If possible, manage such critical limits before the PHP process (e.g. in your Nginx config, your Cloudfire account or using AWS request throttling).
This is really nice feature. Good job!
It would be nice to have an annotation for this feature !
Great functionality, but I'm wondering whether this could verify the limits without initiating a PHP process. Because if we have 1,000 requests of this kind, it becomes heavy for the server even though these requests will not result in 200 responses
Nice feature.
Nice. It 's been useful to limit attempts on a login's form.
I think there is a mistake in the exemple. The variable $limiter is create but not used and we use the anonymousApiLimiter to validate. In the documentation, it's the $limiter use to validate.
@philippe you are right! We've just fixed the variable name in the code example.