Skip to content

Commit a91bebe

Browse files
committed
minor #14918 [RateLimiter][Security] Document login throttling and clarify DoS protection (wouterj)
This PR was squashed before being merged into the 5.2 branch. Discussion ---------- [RateLimiter][Security] Document login throttling and clarify DoS protection This PR started as "clarifying Symfony's rate limiter use-case compared to rate limiters outside PHP" (first commit). I wanted to also add some guidelines on brute force attack protection beyond limiting login attempts, but discovered login throttling wasn't documented yet. So this PR now also documents login throttling :) Fixes #14251 Commits ------- 88a52da [RateLimiter][Security] Document login throttling and clarify DoS protection
2 parents a8c5911 + 88a52da commit a91bebe

File tree

2 files changed

+120
-0
lines changed

2 files changed

+120
-0
lines changed

rate_limiter.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@ Symfony uses these rate limiters in built-in features like "login throttling",
1616
which limits how many failed login attempts a user can make in a given period of
1717
time, but you can use them for your own features too.
1818

19+
.. caution::
20+
21+
By definition, the Symfony rate limiters require Symfony to be booted
22+
in a PHP process. This makes them not useful to protect against `DoS attacks`_.
23+
Such protections must consume the least resources possible. Consider
24+
using `Apache mod_ratelimit`_, `NGINX rate limiting`_ or proxies (like
25+
AWS or Cloudflare) to prevent your server from being overwhelmed.
26+
1927
.. _rate-limiter-policies:
2028

2129
Rate Limiting Policies
@@ -314,5 +322,8 @@ Symfony application. If you prefer to change that, use the ``lock_factory`` and
314322
# the value is the name of any lock defined in your application
315323
lock_factory: 'app.rate_limiter_lock'
316324
325+
.. _`DoS attacks`: https://cheatsheetseries.owasp.org/cheatsheets/Denial_of_Service_Cheat_Sheet.html
326+
.. _`Apache mod_ratelimit`: https://httpd.apache.org/docs/current/mod/mod_ratelimit.html
327+
.. _`NGINX rate limiting`: https://www.nginx.com/blog/rate-limiting-nginx/
317328
.. _`token bucket algorithm`: https://en.wikipedia.org/wiki/Token_bucket
318329
.. _`PHP date relative formats`: https://www.php.net/datetime.formats.relative

security.rst

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -469,6 +469,113 @@ here are a few common use-cases:
469469
* :doc:`/security/guard_authentication` – see this for the most detailed
470470
description of authenticators and how they work
471471

472+
Limiting Login Attempts
473+
~~~~~~~~~~~~~~~~~~~~~~~
474+
475+
.. versionadded:: 5.2
476+
477+
Login throttling was introduced in Symfony 5.2.
478+
479+
Symfony provides basic protection against `brute force login attacks`_ if
480+
you're using the :doc:`experimental authenticators </security/experimental_authenticators>`.
481+
You must enable this using the ``login_throttling`` setting:
482+
483+
.. configuration-block::
484+
485+
.. code-block:: yaml
486+
487+
# config/packages/security.yaml
488+
security:
489+
enable_authenticator_manager: true
490+
491+
firewalls:
492+
# ...
493+
494+
main:
495+
# ...
496+
497+
# by default, the feature allows 5 login attempts per minute
498+
login_throttling: null
499+
500+
# configure the maximum login attempts (per minute)
501+
login_throttling:
502+
max_attempts: 3
503+
504+
# use a custom rate limiter via its service ID
505+
login_throttling:
506+
limiter: app.my_login_rate_limiter
507+
508+
.. code-block:: xml
509+
510+
<!-- config/packages/security.xml -->
511+
<?xml version="1.0" encoding="UTF-8"?>
512+
<srv:container xmlns="http://symfony.com/schema/dic/security"
513+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
514+
xmlns:srv="http://symfony.com/schema/dic/services"
515+
xsi:schemaLocation="http://symfony.com/schema/dic/services
516+
https://symfony.com/schema/dic/services/services-1.0.xsd
517+
http://symfony.com/schema/dic/security
518+
https://symfony.com/schema/dic/security/security-1.0.xsd">
519+
520+
<config enable-authenticator-manager="true">
521+
<!-- ... -->
522+
523+
<firewall name="main">
524+
<!-- by default, the feature allows 5 login attempts per minute -->
525+
<login-throttling/>
526+
527+
<!-- configure the maximum login attempts (per minute) -->
528+
<login-throttling max-attempts="3"/>
529+
530+
<!-- use a custom rate limiter via its service ID -->
531+
<login-throttling limiter="app.my_login_rate_limiter"/>
532+
</firewall>
533+
</config>
534+
</srv:container>
535+
536+
.. code-block:: php
537+
538+
// config/packages/security.php
539+
$container->loadFromExtension('security', [
540+
'enable_authenticator_manager' => true,
541+
542+
'firewalls' => [
543+
// ...
544+
545+
'main' => [
546+
// by default, the feature allows 5 login attempts per minute
547+
'login_throttling' => null,
548+
549+
// configure the maximum login attempts (per minute)
550+
'login_throttling' => [
551+
'max_attempts' => 3,
552+
],
553+
554+
// use a custom rate limiter via its service ID
555+
'login_throttling' => [
556+
'limiter' => 'app.my_login_rate_limiter',
557+
],
558+
],
559+
],
560+
]);
561+
562+
By default, login attempts are limited on ``max_attempts`` (default: 5)
563+
failed requests for ``IP address + username`` and ``5 * max_attempts``
564+
failed requests for ``IP address``. The second limit protects against an
565+
attacker using multiple usernames from bypassing the first limit, without
566+
distrupting normal users on big networks (such as offices).
567+
568+
If you need a more complex limiting algorithm, create a class that implements
569+
:class:`Symfony\\Component\\HttpFoundation\\RateLimiter\\RequestRateLimiterInterface`
570+
and set the ``limiter`` option to its service ID.
571+
572+
.. tip::
573+
574+
Limiting the failed login attempts is only one basic protection against
575+
brute force attacks. The `OWASP Brute Force Attacks`_ guidelines mention
576+
several other protections that you should consider depending on the
577+
level of protection required.
578+
472579
.. _`security-authorization`:
473580
.. _denying-access-roles-and-other-authorization:
474581

@@ -1257,5 +1364,7 @@ Authorization (Denying Access)
12571364

12581365
.. _`FrameworkExtraBundle documentation`: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/index.html
12591366
.. _`HWIOAuthBundle`: https://github.com/hwi/HWIOAuthBundle
1367+
.. _`OWASP Brute Force Attacks`: https://owasp.org/www-community/controls/Blocking_Brute_Force_Attacks
1368+
.. _`brute force login attacks`: https://owasp.org/www-community/controls/Blocking_Brute_Force_Attacks
12601369
.. _`Symfony Security screencast series`: https://symfonycasts.com/screencast/symfony-security
12611370
.. _`MakerBundle`: https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html

0 commit comments

Comments
 (0)