From 286f00cac7a3a40bed387b6952f733dc0401a0e3 Mon Sep 17 00:00:00 2001 From: Kevin Weber Date: Sat, 23 May 2015 10:00:54 -0400 Subject: [PATCH 1/6] Added security event descriptions to security component authentication page. --- components/security/authentication.rst | 48 ++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/components/security/authentication.rst b/components/security/authentication.rst index 00425a5d8f3..f720878a737 100644 --- a/components/security/authentication.rst +++ b/components/security/authentication.rst @@ -267,5 +267,53 @@ in) is correct, you can use:: $user->getSalt() ); +Events +------ + +The security component provides 4 related events: + +=============================== ================================================ ========================================================================= +Name Event Constant Argument Passed to the Listener +=============================== ================================================ ========================================================================= +security.authentication.success ``AuthenticationEvents::AUTHENTICATION_SUCCESS`` :class:`Symfony\Component\Security\Core\Event\AuthenticationEvent` +security.authentication.failure ``AuthenticationEvents::AUTHENTICATION_FAILURE`` :class:`Symfony\Component\Security\Core\Event\AuthenticationFailureEvent` +security.interactive_login ``SecurityEvents::INTERACTIVE_LOGIN`` :class:`Symfony\Component\Security\Http\Event\InteractiveLoginEvent` +security.switch_user ``SecurityEvents::SWITCH_USER`` :class:`Symfony\Component\Security\Http\Event\SwitchUserEvent` +=============================== ================================================ ========================================================================= + +Authentication Events +~~~~~~~~~~~~~~~~~~~~~ + +When a provider authenticates the user, a ``security.authentication.success`` +event is dispatched. Likewise, when no providers authenticate the user, +a ``security.authentication.failure`` event is dispatched. You +could listen on the ``security.authentication.failure`` event, for example, +in order to log failed login attempts. + +It is important to remember that one authentication event is always triggered +when a request points to a secured area. + +Security Events +~~~~~~~~~~~~~~~ + +The ``security.interactive_login`` event is triggered after a user has actively +logged into your website. It is important to distinguish this action from +non-interactive authentication methods, such as: + +* authentication based on a "remember me" cookie. +* authentication based on your session. +* authentication using a HTTP basic or HTTP digest header. + +You could listen on the ``security.interactive_login`` event, for example, in +order to give your user a welcome flash message every time they log in. + +The ``security.switch_user`` event is triggered every time you activate +the ``switch_user`` firewall listener. + +.. seealso:: + + For more information on switching users, see + :doc:`/cookbook/security/impersonating_user`. + .. _`CVE-2013-5750`: http://symfony.com/blog/cve-2013-5750-security-issue-in-fosuserbundle-login-form .. _`BasePasswordEncoder::checkPasswordLength`: https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Core/Encoder/BasePasswordEncoder.php From 9b2e9d867de8fb3eb500e31f901232fc434d47c5 Mon Sep 17 00:00:00 2001 From: Kevin Weber Date: Sat, 23 May 2015 10:15:58 -0400 Subject: [PATCH 2/6] Better section titles for security events on authentication page. --- components/security/authentication.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/security/authentication.rst b/components/security/authentication.rst index f720878a737..43f8c878faa 100644 --- a/components/security/authentication.rst +++ b/components/security/authentication.rst @@ -267,10 +267,10 @@ in) is correct, you can use:: $user->getSalt() ); -Events ------- +Authentication Events +--------------------- -The security component provides 4 related events: +The security component provides 4 related authentication events: =============================== ================================================ ========================================================================= Name Event Constant Argument Passed to the Listener @@ -281,8 +281,8 @@ security.interactive_login ``SecurityEvents::INTERACTIVE_LOGIN`` security.switch_user ``SecurityEvents::SWITCH_USER`` :class:`Symfony\Component\Security\Http\Event\SwitchUserEvent` =============================== ================================================ ========================================================================= -Authentication Events -~~~~~~~~~~~~~~~~~~~~~ +Authentication Success and Failure Events +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When a provider authenticates the user, a ``security.authentication.success`` event is dispatched. Likewise, when no providers authenticate the user, From 5bdfd71b4789b5e69f6d320349cb5038b0d43aa3 Mon Sep 17 00:00:00 2001 From: Kevin Weber Date: Sat, 23 May 2015 13:00:29 -0400 Subject: [PATCH 3/6] Better formatting for authentication tip. --- components/security/authentication.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/security/authentication.rst b/components/security/authentication.rst index 43f8c878faa..9f2a2d8b084 100644 --- a/components/security/authentication.rst +++ b/components/security/authentication.rst @@ -290,8 +290,10 @@ a ``security.authentication.failure`` event is dispatched. You could listen on the ``security.authentication.failure`` event, for example, in order to log failed login attempts. -It is important to remember that one authentication event is always triggered -when a request points to a secured area. +.. tip:: + + One of the authentication events is always triggered when a request points + to a secured area. Security Events ~~~~~~~~~~~~~~~ From f15bea451910fbba564ace171ba997278941dadc Mon Sep 17 00:00:00 2001 From: Kevin Weber Date: Sat, 23 May 2015 13:01:29 -0400 Subject: [PATCH 4/6] Added new cookbook page to security index. --- cookbook/security/index.rst | 1 + cookbook/security/throttle_failed_login.rst | 117 ++++++++++++++++++++ 2 files changed, 118 insertions(+) create mode 100644 cookbook/security/throttle_failed_login.rst diff --git a/cookbook/security/index.rst b/cookbook/security/index.rst index 5bf643c10e8..04f05dc9efb 100644 --- a/cookbook/security/index.rst +++ b/cookbook/security/index.rst @@ -22,3 +22,4 @@ Security csrf_in_login_form access_control multiple_user_providers + throttle_failed_login diff --git a/cookbook/security/throttle_failed_login.rst b/cookbook/security/throttle_failed_login.rst new file mode 100644 index 00000000000..e96762b70d6 --- /dev/null +++ b/cookbook/security/throttle_failed_login.rst @@ -0,0 +1,117 @@ +.. index:: + single: Security; Throttle Failed Login + +How to Throttle Failed Login Attempts +===================================== + +Sometimes, it's useful to throttle login attempts when you encounter multiple +recent failed logins. This can be useful in combatting brute-force +password-guessing login attacks. This can be done by implementing a +``security.authentication.failure`` listener to log failed login attempts, and +a security provider decorator to deny login attempts from the same IP address. + +Authentication Failure Listener +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The purpose of this authentication failure listener is to persist the ip address +and any other data of the client. The example here uses a doctrine table to +persist the data, but you could use another method (Redis, for example). + +.. code-block:: php + + namespace AppBundle\Security\Authentication\Listener; + + use Doctrine\ORM\EntityRepositoryInterface; + use Symfony\Component\HttpFoundation\RequestStack; + use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent; + + class LogFailedLoginAttempt + { + /** + * The doctrine repository to which the failed login attempt will be + * persisted. + * + * @var EntityRepositoryInterface + */ + private $repository; + + /** + * The current request contains the ip address and other $_SERVER globals + * to persist. + * + * @var RequestStack + */ + private $requestStack; + + public function __construct(RequestStack $requestStack, EntityRepositoryInterface $repository) + { + $this->repository = $repository; + $this->requestStack = $requestStack; + } + + public function onAuthenticationFailureEvent(AuthenticationFailureEvent $event) + { + $this->repository->logAuthenicationFailure( + $event->getToken(), + $this->requestStack->getCurrentRequest() + ); + } + } + +Now you are logging all the relevant details about every failed login attempt. + +Security Provider Decorator +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This security provider will decorate another security provider and will reject +any authentication attempts it needs to throttle. + +.. code-block:: php + + namespace AppBundle\Security\Authentication\Provider; + + use Symfony\Component\Security\Core\Exception\AuthenticationException; + use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface; + use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; + + class LoginThrottleProvider implements AuthenticationProviderInterface + { + /** + * @var AuthenticationProviderInterface + */ + private $decoratedProvider; + + /** + * The throttle service decides whether to throttle a certain + * ip address or not. + */ + private $throttleService; + + public function __construct(AuthenticationProviderInterface $provider, $throttleService) + { + $this->decoratedProvider = $provider; + $this->throttleService = $throttleService; + } + + public function authenticate(TokenInterface $token) + { + if ($this->throttleService->isThrottled($token)) { + throw new AuthenticationException( + 'Too many failed authentication attempts.' + ); + } + + return $this->decoratedProvider->authenticate($token); + } + + public function supports(TokenInterface $token) + { + return $this->decoratedProvider->supports($token); + } + } + +The implementation of the throttle service is outside the scope of this +documentation and will depend on your application's needs. It is common +for an application to require additional means of authentication when +multiple failed logins are detected, such as the addition of a CAPTCHA +to the login page, or requiring two-factor authentication. From a14bd071066af5f0d72fd000a730047f57f09bf2 Mon Sep 17 00:00:00 2001 From: Kevin Weber Date: Mon, 28 Dec 2015 16:19:44 -0500 Subject: [PATCH 5/6] Security - Authentication - removed inaccurate tip. --- components/security/authentication.rst | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/components/security/authentication.rst b/components/security/authentication.rst index 9f2a2d8b084..87657029f76 100644 --- a/components/security/authentication.rst +++ b/components/security/authentication.rst @@ -285,15 +285,11 @@ Authentication Success and Failure Events ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When a provider authenticates the user, a ``security.authentication.success`` -event is dispatched. Likewise, when no providers authenticate the user, -a ``security.authentication.failure`` event is dispatched. You -could listen on the ``security.authentication.failure`` event, for example, -in order to log failed login attempts. - -.. tip:: - - One of the authentication events is always triggered when a request points - to a secured area. +event is dispatched. Likewise, when a provider attempts authentication but +fails (i.e. throws an ``AuthenticationException``), a +``security.authentication.failure`` event is dispatched. You could listen on +the ``security.authentication.failure`` event, for example, in order to log +failed login attempts. Security Events ~~~~~~~~~~~~~~~ From 0dbabfe7ff2375163fa8dc191ac2190cc2fd83f7 Mon Sep 17 00:00:00 2001 From: Kevin Weber Date: Mon, 28 Dec 2015 16:22:07 -0500 Subject: [PATCH 6/6] Security - Cookbook - removed bad example. --- cookbook/security/index.rst | 1 - cookbook/security/throttle_failed_login.rst | 117 -------------------- 2 files changed, 118 deletions(-) delete mode 100644 cookbook/security/throttle_failed_login.rst diff --git a/cookbook/security/index.rst b/cookbook/security/index.rst index 04f05dc9efb..5bf643c10e8 100644 --- a/cookbook/security/index.rst +++ b/cookbook/security/index.rst @@ -22,4 +22,3 @@ Security csrf_in_login_form access_control multiple_user_providers - throttle_failed_login diff --git a/cookbook/security/throttle_failed_login.rst b/cookbook/security/throttle_failed_login.rst deleted file mode 100644 index e96762b70d6..00000000000 --- a/cookbook/security/throttle_failed_login.rst +++ /dev/null @@ -1,117 +0,0 @@ -.. index:: - single: Security; Throttle Failed Login - -How to Throttle Failed Login Attempts -===================================== - -Sometimes, it's useful to throttle login attempts when you encounter multiple -recent failed logins. This can be useful in combatting brute-force -password-guessing login attacks. This can be done by implementing a -``security.authentication.failure`` listener to log failed login attempts, and -a security provider decorator to deny login attempts from the same IP address. - -Authentication Failure Listener -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The purpose of this authentication failure listener is to persist the ip address -and any other data of the client. The example here uses a doctrine table to -persist the data, but you could use another method (Redis, for example). - -.. code-block:: php - - namespace AppBundle\Security\Authentication\Listener; - - use Doctrine\ORM\EntityRepositoryInterface; - use Symfony\Component\HttpFoundation\RequestStack; - use Symfony\Component\Security\Core\Event\AuthenticationFailureEvent; - - class LogFailedLoginAttempt - { - /** - * The doctrine repository to which the failed login attempt will be - * persisted. - * - * @var EntityRepositoryInterface - */ - private $repository; - - /** - * The current request contains the ip address and other $_SERVER globals - * to persist. - * - * @var RequestStack - */ - private $requestStack; - - public function __construct(RequestStack $requestStack, EntityRepositoryInterface $repository) - { - $this->repository = $repository; - $this->requestStack = $requestStack; - } - - public function onAuthenticationFailureEvent(AuthenticationFailureEvent $event) - { - $this->repository->logAuthenicationFailure( - $event->getToken(), - $this->requestStack->getCurrentRequest() - ); - } - } - -Now you are logging all the relevant details about every failed login attempt. - -Security Provider Decorator -~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -This security provider will decorate another security provider and will reject -any authentication attempts it needs to throttle. - -.. code-block:: php - - namespace AppBundle\Security\Authentication\Provider; - - use Symfony\Component\Security\Core\Exception\AuthenticationException; - use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface; - use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; - - class LoginThrottleProvider implements AuthenticationProviderInterface - { - /** - * @var AuthenticationProviderInterface - */ - private $decoratedProvider; - - /** - * The throttle service decides whether to throttle a certain - * ip address or not. - */ - private $throttleService; - - public function __construct(AuthenticationProviderInterface $provider, $throttleService) - { - $this->decoratedProvider = $provider; - $this->throttleService = $throttleService; - } - - public function authenticate(TokenInterface $token) - { - if ($this->throttleService->isThrottled($token)) { - throw new AuthenticationException( - 'Too many failed authentication attempts.' - ); - } - - return $this->decoratedProvider->authenticate($token); - } - - public function supports(TokenInterface $token) - { - return $this->decoratedProvider->supports($token); - } - } - -The implementation of the throttle service is outside the scope of this -documentation and will depend on your application's needs. It is common -for an application to require additional means of authentication when -multiple failed logins are detected, such as the addition of a CAPTCHA -to the login page, or requiring two-factor authentication.