Skip to content

Commit ab70528

Browse files
committed
feature#6554 [Security] Added Security\Csrf sub-component with better token generation (bschussek)
This PR was merged into the master branch. Discussion ---------- [Security] Added Security\Csrf sub-component with better token generation | Q | A | ------------- | --- | Bug fix? | yes | New feature? | no | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | TODO **Update September 27, 2013** This PR simplifies the CSRF mechanism to generate completely random tokens. A random token is generated once per ~~intention~~ token ID and then stored in the session. Tokens are valid until the session expires. Since the CSRF token generator depends on `StringUtils` and `SecureRandom` from Security\Core, and since Security\Http currently depends on the Form component for token generation, I decided to add a new Security\Csrf sub-component that contains the improved CSRF token generator. Consequences: * Security\Http now depends on Security\Csrf instead of Form * Form now optionally depends on Security\Csrf * The configuration for the "security.secure_random" service and the "security.csrf.*" services was moved to FrameworkBundle to guarantee BC In the new Security\Csrf sub-component, I tried to improve the naming where I could do so without breaking BC: * CSRF "providers" are now called "token generators" * CSRF "intentions" are now called "token IDs", because that's really what they are ##### TODO - [ ] The documentation needs to be checked for references to the configuration of the application secret. Remarks that the secret is used for CSRF protection need to be removed. - [ ] Add aliases "csrf_token_generator" and "csrf_token_id" for "csrf_provider" and "intention" in the SecurityBundle configuration - [x] Make sure `SecureRandom` never blocks for `CsrfTokenGenerator` Commits ------- 7f02304 [Security] Added missing PHPDoc tag 2e04e32 Updated Composer dependencies to require the Security\Csrf component where necessary bf85e83 [FrameworkBundle][SecurityBundle] Added service configuration for the new Security CSRF sub-component 2048cf6 [Form] Deprecated the CSRF implementation and added an optional dependency to the Security CSRF sub-component instead 85d4959 [Security] Changed Security HTTP sub-component to depend on CSRF sub-component instead of Form 1bf1640 [Security] Added CSRF sub-component
2 parents e046848 + fc8e83c commit ab70528

File tree

4 files changed

+27
-25
lines changed

4 files changed

+27
-25
lines changed

Firewall/LogoutListener.php

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,12 @@
1111

1212
namespace Symfony\Component\Security\Http\Firewall;
1313

14-
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
1514
use Symfony\Component\HttpFoundation\Request;
1615
use Symfony\Component\HttpFoundation\Response;
1716
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
1817
use Symfony\Component\Security\Core\SecurityContextInterface;
1918
use Symfony\Component\Security\Core\Exception\LogoutException;
19+
use Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface;
2020
use Symfony\Component\Security\Http\HttpUtils;
2121
use Symfony\Component\Security\Http\Logout\LogoutHandlerInterface;
2222
use Symfony\Component\Security\Http\Logout\LogoutSuccessHandlerInterface;
@@ -34,18 +34,18 @@ class LogoutListener implements ListenerInterface
3434
private $handlers;
3535
private $successHandler;
3636
private $httpUtils;
37-
private $csrfProvider;
37+
private $csrfTokenGenerator;
3838

3939
/**
4040
* Constructor.
4141
*
4242
* @param SecurityContextInterface $securityContext
43-
* @param HttpUtils $httpUtils An HttpUtilsInterface instance
44-
* @param LogoutSuccessHandlerInterface $successHandler A LogoutSuccessHandlerInterface instance
45-
* @param array $options An array of options to process a logout attempt
46-
* @param CsrfProviderInterface $csrfProvider A CsrfProviderInterface instance
43+
* @param HttpUtils $httpUtils An HttpUtilsInterface instance
44+
* @param LogoutSuccessHandlerInterface $successHandler A LogoutSuccessHandlerInterface instance
45+
* @param array $options An array of options to process a logout attempt
46+
* @param CsrfTokenGeneratorInterface $csrfTokenGenerator A CsrfTokenGeneratorInterface instance
4747
*/
48-
public function __construct(SecurityContextInterface $securityContext, HttpUtils $httpUtils, LogoutSuccessHandlerInterface $successHandler, array $options = array(), CsrfProviderInterface $csrfProvider = null)
48+
public function __construct(SecurityContextInterface $securityContext, HttpUtils $httpUtils, LogoutSuccessHandlerInterface $successHandler, array $options = array(), CsrfTokenGeneratorInterface $csrfTokenGenerator = null)
4949
{
5050
$this->securityContext = $securityContext;
5151
$this->httpUtils = $httpUtils;
@@ -55,7 +55,7 @@ public function __construct(SecurityContextInterface $securityContext, HttpUtils
5555
'logout_path' => '/logout',
5656
), $options);
5757
$this->successHandler = $successHandler;
58-
$this->csrfProvider = $csrfProvider;
58+
$this->csrfTokenGenerator = $csrfTokenGenerator;
5959
$this->handlers = array();
6060
}
6161

@@ -72,7 +72,7 @@ public function addHandler(LogoutHandlerInterface $handler)
7272
/**
7373
* Performs the logout if requested
7474
*
75-
* If a CsrfProviderInterface instance is available, it will be used to
75+
* If a CsrfTokenGeneratorInterface instance is available, it will be used to
7676
* validate the request.
7777
*
7878
* @param GetResponseEvent $event A GetResponseEvent instance
@@ -88,10 +88,10 @@ public function handle(GetResponseEvent $event)
8888
return;
8989
}
9090

91-
if (null !== $this->csrfProvider) {
91+
if (null !== $this->csrfTokenGenerator) {
9292
$csrfToken = $request->get($this->options['csrf_parameter'], null, true);
9393

94-
if (false === $this->csrfProvider->isCsrfTokenValid($this->options['intention'], $csrfToken)) {
94+
if (false === $this->csrfTokenGenerator->isCsrfTokenValid($this->options['intention'], $csrfToken)) {
9595
throw new LogoutException('Invalid CSRF token.');
9696
}
9797
}

Firewall/SimpleFormAuthenticationListener.php

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@
1313

1414
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
1515
use Symfony\Component\HttpFoundation\Request;
16+
use Symfony\Component\Security\Core\Exception\InvalidCsrfTokenException;
17+
use Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface;
1618
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
1719
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
1820
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface;
19-
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
2021
use Symfony\Component\Security\Core\Authentication\SimpleFormAuthenticatorInterface;
2122
use Symfony\Component\Security\Core\SecurityContextInterface;
2223
use Symfony\Component\Security\Http\HttpUtils;
@@ -29,7 +30,7 @@
2930
class SimpleFormAuthenticationListener extends AbstractAuthenticationListener
3031
{
3132
private $simpleAuthenticator;
32-
private $csrfProvider;
33+
private $csrfTokenGenerator;
3334

3435
/**
3536
* Constructor.
@@ -46,16 +47,16 @@ class SimpleFormAuthenticationListener extends AbstractAuthenticationListener
4647
* @param LoggerInterface $logger A LoggerInterface instance
4748
* @param EventDispatcherInterface $dispatcher An EventDispatcherInterface instance
4849
* @param SimpleFormAuthenticatorInterface $simpleAuthenticator A SimpleFormAuthenticatorInterface instance
49-
* @param CsrfProviderInterface $csrfProvider A CsrfProviderInterface instance
50+
* @param CsrfTokenGeneratorInterface $csrfTokenGenerator A CsrfTokenGeneratorInterface instance
5051
*/
51-
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null, SimpleFormAuthenticatorInterface $simpleAuthenticator = null)
52+
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfTokenGeneratorInterface $csrfTokenGenerator = null, SimpleFormAuthenticatorInterface $simpleAuthenticator = null)
5253
{
5354
if (!$simpleAuthenticator) {
5455
throw new \InvalidArgumentException('Missing simple authenticator');
5556
}
5657

5758
$this->simpleAuthenticator = $simpleAuthenticator;
58-
$this->csrfProvider = $csrfProvider;
59+
$this->csrfTokenGenerator = $csrfTokenGenerator;
5960

6061
$options = array_merge(array(
6162
'username_parameter' => '_username',
@@ -84,10 +85,10 @@ protected function requiresAuthentication(Request $request)
8485
*/
8586
protected function attemptAuthentication(Request $request)
8687
{
87-
if (null !== $this->csrfProvider) {
88+
if (null !== $this->csrfTokenGenerator) {
8889
$csrfToken = $request->get($this->options['csrf_parameter'], null, true);
8990

90-
if (false === $this->csrfProvider->isCsrfTokenValid($this->options['intention'], $csrfToken)) {
91+
if (false === $this->csrfTokenGenerator->isCsrfTokenValid($this->options['intention'], $csrfToken)) {
9192
throw new InvalidCsrfTokenException('Invalid CSRF token.');
9293
}
9394
}

Firewall/UsernamePasswordFormAuthenticationListener.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@
1111

1212
namespace Symfony\Component\Security\Http\Firewall;
1313

14-
use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface;
1514
use Symfony\Component\HttpFoundation\Request;
1615
use Psr\Log\LoggerInterface;
16+
use Symfony\Component\Security\Csrf\CsrfTokenGeneratorInterface;
1717
use Symfony\Component\Security\Http\Authentication\AuthenticationFailureHandlerInterface;
1818
use Symfony\Component\Security\Http\Authentication\AuthenticationSuccessHandlerInterface;
1919
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
@@ -32,12 +32,12 @@
3232
*/
3333
class UsernamePasswordFormAuthenticationListener extends AbstractAuthenticationListener
3434
{
35-
private $csrfProvider;
35+
private $csrfTokenGenerator;
3636

3737
/**
3838
* {@inheritdoc}
3939
*/
40-
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfProviderInterface $csrfProvider = null)
40+
public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager, SessionAuthenticationStrategyInterface $sessionStrategy, HttpUtils $httpUtils, $providerKey, AuthenticationSuccessHandlerInterface $successHandler, AuthenticationFailureHandlerInterface $failureHandler, array $options = array(), LoggerInterface $logger = null, EventDispatcherInterface $dispatcher = null, CsrfTokenGeneratorInterface $csrfTokenGenerator = null)
4141
{
4242
parent::__construct($securityContext, $authenticationManager, $sessionStrategy, $httpUtils, $providerKey, $successHandler, $failureHandler, array_merge(array(
4343
'username_parameter' => '_username',
@@ -47,7 +47,7 @@ public function __construct(SecurityContextInterface $securityContext, Authentic
4747
'post_only' => true,
4848
), $options), $logger, $dispatcher);
4949

50-
$this->csrfProvider = $csrfProvider;
50+
$this->csrfTokenGenerator = $csrfTokenGenerator;
5151
}
5252

5353
/**
@@ -67,10 +67,10 @@ protected function requiresAuthentication(Request $request)
6767
*/
6868
protected function attemptAuthentication(Request $request)
6969
{
70-
if (null !== $this->csrfProvider) {
70+
if (null !== $this->csrfTokenGenerator) {
7171
$csrfToken = $request->get($this->options['csrf_parameter'], null, true);
7272

73-
if (false === $this->csrfProvider->isCsrfTokenValid($this->options['intention'], $csrfToken)) {
73+
if (false === $this->csrfTokenGenerator->isCsrfTokenValid($this->options['intention'], $csrfToken)) {
7474
throw new InvalidCsrfTokenException('Invalid CSRF token.');
7575
}
7676
}

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@
2525
"require-dev": {
2626
"symfony/form": "~2.0",
2727
"symfony/routing": "~2.2",
28+
"symfony/security-csrf": "~2.4",
2829
"psr/log": "~1.0"
2930
},
3031
"suggest": {
31-
"symfony/form": "",
32+
"symfony/security-csrf": "",
3233
"symfony/routing": ""
3334
},
3435
"autoload": {

0 commit comments

Comments
 (0)