@@ -550,11 +550,6 @@ You must enable this using the ``login_throttling`` setting:
550
550
'login_throttling' => [
551
551
'max_attempts' => 3,
552
552
],
553
-
554
- // use a custom rate limiter via its service ID
555
- 'login_throttling' => [
556
- 'limiter' => 'app.my_login_rate_limiter',
557
- ],
558
553
],
559
554
],
560
555
]);
@@ -565,17 +560,148 @@ failed requests for ``IP address``. The second limit protects against an
565
560
attacker using multiple usernames from bypassing the first limit, without
566
561
distrupting normal users on big networks (such as offices).
567
562
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
563
.. tip ::
573
564
574
565
Limiting the failed login attempts is only one basic protection against
575
566
brute force attacks. The `OWASP Brute Force Attacks `_ guidelines mention
576
567
several other protections that you should consider depending on the
577
568
level of protection required.
578
569
570
+ If you need a more complex limiting algorithm, create a class that implements
571
+ :class: `Symfony\\ Component\\ HttpFoundation\\ RateLimiter\\ RequestRateLimiterInterface `
572
+ (or use
573
+ :class: `Symfony\\ Component\\ Security\\ Http\\ RateLimiter\\ DefaultLoginRateLimiter `)
574
+ and set the ``limiter `` option to its service ID:
575
+
576
+ .. configuration-block ::
577
+
578
+ .. code-block :: yaml
579
+
580
+ # config/packages/security.yaml
581
+ framework :
582
+ rate_limiter :
583
+ # define 2 rate limiters (one for username+IP, the other for IP)
584
+ username_ip_login :
585
+ policy : token_bucket
586
+ limit : 5
587
+ rate : { interval: '5 minutes' }
588
+
589
+ ip_login :
590
+ policy : sliding_window
591
+ limit : 50
592
+ interval : ' 15 minutes'
593
+
594
+ services :
595
+ # our custom login rate limiter
596
+ app.login_rate_limiter :
597
+ class : Symfony\Component\Security\Http\RateLimiter\DefaultLoginRateLimiter
598
+ arguments :
599
+ # globalFactory is the limiter for IP
600
+ $globalFactory : ' @limiter.ip_login'
601
+ # localFactory is the limiter for username+IP
602
+ $localFactory : ' @limiter.username_ip_login'
603
+
604
+ security :
605
+ firewalls :
606
+ main :
607
+ # use a custom rate limiter via its service ID
608
+ login_throttling :
609
+ limiter : app.login_rate_limiter
610
+
611
+ .. code-block :: xml
612
+
613
+ <!-- config/packages/security.xml -->
614
+ <?xml version =" 1.0" encoding =" UTF-8" ?>
615
+ <srv : container xmlns =" http://symfony.com/schema/dic/security"
616
+ xmlns : xsi =" http://www.w3.org/2001/XMLSchema-instance"
617
+ xmlns : framework =" http://symfony.com/schema/dic/symfony"
618
+ xmlns : srv =" http://symfony.com/schema/dic/services"
619
+ xsi : schemaLocation =" http://symfony.com/schema/dic/services
620
+ https://symfony.com/schema/dic/services/services-1.0.xsd
621
+ http://symfony.com/schema/dic/symfony
622
+ https://symfony.com/schema/dic/symfony/symfony-1.0.xsd
623
+ http://symfony.com/schema/dic/security
624
+ https://symfony.com/schema/dic/security/security-1.0.xsd" >
625
+
626
+ <framework : config >
627
+ <framework : rate-limiter >
628
+ <!-- define 2 rate limiters (one for username+IP, the other for IP) -->
629
+ <framework : limiter name =" username_ip_login"
630
+ policy =" token_bucket"
631
+ limit =" 5"
632
+ >
633
+ <framework : rate interval =" 5 minutes" />
634
+ </framework : limiter >
635
+
636
+ <framework : limiter name =" ip_login"
637
+ policy =" sliding_window"
638
+ limit =" 50"
639
+ interval =" 15 minutes"
640
+ />
641
+ </framework : rate-limiter >
642
+ </framework : config >
643
+
644
+ <srv : services >
645
+ <!-- our custom login rate limiter -->
646
+ <srv : service id =" app.login_rate_limiter"
647
+ class =" Symfony\Component\Security\Http\RateLimiter\DefaultLoginRateLimiter"
648
+ >
649
+ <!-- 1st argument is the limiter for IP -->
650
+ <srv : argument type =" service" id =" limiter.ip_login" />
651
+ <1-- 2nd argument is the limiter for username+IP -->
652
+ <srv : argument type =" service" id =" limiter.username_ip_login" />
653
+ </srv : service >
654
+ </srv : services >
655
+
656
+ <config >
657
+ <firewall name =" main" >
658
+ <!-- use a custom rate limiter via its service ID -->
659
+ <login-throttling limiter =" app.login_rate_limiter" />
660
+ </firewall >
661
+ </config >
662
+ </srv : container >
663
+
664
+ .. code-block :: php
665
+
666
+ // config/packages/security.php
667
+ use Symfony\Component\DependencyInjection\Reference;
668
+ use Symfony\Component\Security\Http\RateLimiter\DefaultLoginRateLimiter;
669
+
670
+ $container->loadFromExtension('framework', [
671
+ 'rate_limiter' => [
672
+ // define 2 rate limiters (one for username+IP, the other for IP)
673
+ 'username_ip_login' => [
674
+ 'policy' => 'token_bucket',
675
+ 'limit' => 5,
676
+ 'rate' => [ 'interval' => '5 minutes' ],
677
+ ],
678
+ 'ip_login' => [
679
+ 'policy' => 'sliding_window',
680
+ 'limit' => 50,
681
+ 'interval' => '15 minutes',
682
+ ],
683
+ ],
684
+ ]);
685
+
686
+ $container->register('app.login_rate_limiter', DefaultLoginRateLimiter::class)
687
+ ->setArguments([
688
+ // 1st argument is the limiter for IP
689
+ new Reference('limiter.ip_login'),
690
+ // 2nd argument is the limiter for username+IP
691
+ new Reference('limiter.username_ip_login'),
692
+ ]);
693
+
694
+ $container->loadFromExtension('security', [
695
+ 'firewalls' => [
696
+ 'main' => [
697
+ // use a custom rate limiter via its service ID
698
+ 'login_throttling' =>
699
+ 'limiter' => 'app.login_rate_limiter',
700
+ ],
701
+ ],
702
+ ],
703
+ ]);
704
+
579
705
.. _`security-authorization` :
580
706
.. _denying-access-roles-and-other-authorization :
581
707
0 commit comments