Skip to content

Commit f15bea4

Browse files
author
Kevin Weber
committed
Added new cookbook page to security index.
1 parent 5bdfd71 commit f15bea4

File tree

2 files changed

+118
-0
lines changed

2 files changed

+118
-0
lines changed

cookbook/security/index.rst

+1
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,4 @@ Security
2222
csrf_in_login_form
2323
access_control
2424
multiple_user_providers
25+
throttle_failed_login
+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
.. index::
2+
single: Security; Throttle Failed Login
3+
4+
How to Throttle Failed Login Attempts
5+
=====================================
6+
7+
Sometimes, it's useful to throttle login attempts when you encounter multiple
8+
recent failed logins. This can be useful in combatting brute-force
9+
password-guessing login attacks. This can be done by implementing a
10+
``security.authentication.failure`` listener to log failed login attempts, and
11+
a security provider decorator to deny login attempts from the same IP address.
12+
13+
Authentication Failure Listener
14+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
15+
16+
The purpose of this authentication failure listener is to persist the ip address
17+
and any other data of the client. The example here uses a doctrine table to
18+
persist the data, but you could use another method (Redis, for example).
19+
20+
.. code-block:: php
21+
22+
namespace AppBundle\Security\Authentication\Listener;
23+
24+
use Doctrine\ORM\EntityRepositoryInterface;
25+
use Symfony\Component\HttpFoundation\RequestStack;
26+
use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent;
27+
28+
class LogFailedLoginAttempt
29+
{
30+
/**
31+
* The doctrine repository to which the failed login attempt will be
32+
* persisted.
33+
*
34+
* @var EntityRepositoryInterface
35+
*/
36+
private $repository;
37+
38+
/**
39+
* The current request contains the ip address and other $_SERVER globals
40+
* to persist.
41+
*
42+
* @var RequestStack
43+
*/
44+
private $requestStack;
45+
46+
public function __construct(RequestStack $requestStack, EntityRepositoryInterface $repository)
47+
{
48+
$this->repository = $repository;
49+
$this->requestStack = $requestStack;
50+
}
51+
52+
public function onAuthenticationFailureEvent(AuthenticationFailureEvent $event)
53+
{
54+
$this->repository->logAuthenicationFailure(
55+
$event->getToken(),
56+
$this->requestStack->getCurrentRequest()
57+
);
58+
}
59+
}
60+
61+
Now you are logging all the relevant details about every failed login attempt.
62+
63+
Security Provider Decorator
64+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
65+
66+
This security provider will decorate another security provider and will reject
67+
any authentication attempts it needs to throttle.
68+
69+
.. code-block:: php
70+
71+
namespace AppBundle\Security\Authentication\Provider;
72+
73+
use Symfony\Component\Security\Core\Exception\AuthenticationException;
74+
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
75+
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
76+
77+
class LoginThrottleProvider implements AuthenticationProviderInterface
78+
{
79+
/**
80+
* @var AuthenticationProviderInterface
81+
*/
82+
private $decoratedProvider;
83+
84+
/**
85+
* The throttle service decides whether to throttle a certain
86+
* ip address or not.
87+
*/
88+
private $throttleService;
89+
90+
public function __construct(AuthenticationProviderInterface $provider, $throttleService)
91+
{
92+
$this->decoratedProvider = $provider;
93+
$this->throttleService = $throttleService;
94+
}
95+
96+
public function authenticate(TokenInterface $token)
97+
{
98+
if ($this->throttleService->isThrottled($token)) {
99+
throw new AuthenticationException(
100+
'Too many failed authentication attempts.'
101+
);
102+
}
103+
104+
return $this->decoratedProvider->authenticate($token);
105+
}
106+
107+
public function supports(TokenInterface $token)
108+
{
109+
return $this->decoratedProvider->supports($token);
110+
}
111+
}
112+
113+
The implementation of the throttle service is outside the scope of this
114+
documentation and will depend on your application's needs. It is common
115+
for an application to require additional means of authentication when
116+
multiple failed logins are detected, such as the addition of a CAPTCHA
117+
to the login page, or requiring two-factor authentication.

0 commit comments

Comments
 (0)