Skip to content

Commit 8a6da3f

Browse files
committed
Merge branch '2.7' into 2.8
* 2.7: fixed tests migrate session after remember me authentication prevent timing attacks in digest auth listener mitigate CSRF timing attack vulnerability fix potential timing attack issue
2 parents 92f3179 + 5edc71e commit 8a6da3f

File tree

6 files changed

+85
-7
lines changed

6 files changed

+85
-7
lines changed

src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ public function testCreateServiceMethodCallsWithEscapedParam()
359359
{
360360
$builder = new ContainerBuilder();
361361
$builder->register('bar', 'stdClass');
362-
$builder->register('foo1', 'FooClass')->addMethodCall('setBar', array(array('%%unescape_it%%')));
362+
$builder->register('foo1', 'Bar\FooClass')->addMethodCall('setBar', array(array('%%unescape_it%%')));
363363
$builder->setParameter('value', 'bar');
364364
$this->assertEquals(array('%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the method calls arguments');
365365
}
@@ -368,7 +368,7 @@ public function testCreateServiceProperties()
368368
{
369369
$builder = new ContainerBuilder();
370370
$builder->register('bar', 'stdClass');
371-
$builder->register('foo1', 'FooClass')->setProperty('bar', array('%value%', new Reference('bar'), '%%unescape_it%%'));
371+
$builder->register('foo1', 'Bar\FooClass')->setProperty('bar', array('%value%', new Reference('bar'), '%%unescape_it%%'));
372372
$builder->setParameter('value', 'bar');
373373
$this->assertEquals(array('bar', $builder->get('bar'), '%unescape_it%'), $builder->get('foo1')->bar, '->createService() replaces the values in the properties');
374374
}

src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/DefaultCsrfProvider.php

+13-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider;
1313

14+
use Symfony\Component\Security\Core\Util\StringUtils;
15+
1416
@trigger_error('The '.__NAMESPACE__.'\DefaultCsrfProvider is deprecated since version 2.4 and will be removed in version 3.0. Use the \Symfony\Component\Security\Csrf\TokenStorage\NativeSessionTokenStorage class instead.', E_USER_DEPRECATED);
1517

1618
/**
@@ -61,7 +63,17 @@ public function generateCsrfToken($intention)
6163
*/
6264
public function isCsrfTokenValid($intention, $token)
6365
{
64-
return $token === $this->generateCsrfToken($intention);
66+
$expectedToken = $this->generateCsrfToken($intention);
67+
68+
if (function_exists('hash_equals')) {
69+
return hash_equals($expectedToken, $token);
70+
}
71+
72+
if (class_exists('Symfony\Component\Security\Core\Util\StringUtils')) {
73+
return StringUtils::equals($expectedToken, $token);
74+
}
75+
76+
return $token === $expectedToken;
6577
}
6678

6779
/**

src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Security\Http\Firewall;
1313

1414
use Symfony\Component\Security\Core\User\UserProviderInterface;
15+
use Symfony\Component\Security\Core\Util\StringUtils;
1516
use Symfony\Component\Security\Http\EntryPoint\DigestAuthenticationEntryPoint;
1617
use Psr\Log\LoggerInterface;
1718
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
@@ -99,7 +100,7 @@ public function handle(GetResponseEvent $event)
99100
return;
100101
}
101102

102-
if ($serverDigestMd5 !== $digestAuth->getResponse()) {
103+
if (!StringUtils::equals($serverDigestMd5, $digestAuth->getResponse())) {
103104
if (null !== $this->logger) {
104105
$this->logger->debug('Unexpected response from the DigestAuth received; is the header returning a clear text passwords?', array('expected' => $serverDigestMd5, 'received' => $digestAuth->getResponse()));
105106
}

src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Symfony\Component\Security\Http\SecurityEvents;
2222
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
2323
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
24+
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy;
2425

2526
/**
2627
* RememberMeListener implements authentication capabilities via a cookie.
@@ -56,7 +57,7 @@ public function __construct(TokenStorageInterface $tokenStorage, RememberMeServi
5657
$this->logger = $logger;
5758
$this->dispatcher = $dispatcher;
5859
$this->catchExceptions = $catchExceptions;
59-
$this->sessionStrategy = $sessionStrategy;
60+
$this->sessionStrategy = null === $sessionStrategy ? new SessionAuthenticationStrategy(SessionAuthenticationStrategy::MIGRATE) : $sessionStrategy;
6061
}
6162

6263
/**
@@ -77,7 +78,7 @@ public function handle(GetResponseEvent $event)
7778

7879
try {
7980
$token = $this->authenticationManager->authenticate($token);
80-
if (null !== $this->sessionStrategy && $request->hasSession() && $request->getSession()->isStarted()) {
81+
if ($request->hasSession() && $request->getSession()->isStarted()) {
8182
$this->sessionStrategy->onAuthentication($request, $token);
8283
}
8384
$this->tokenStorage->setToken($token);

src/Symfony/Component/Security/Http/RememberMe/PersistentTokenBasedRememberMeServices.php

+2-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
2222
use Symfony\Component\Security\Core\Util\SecureRandomInterface;
2323
use Psr\Log\LoggerInterface;
24+
use Symfony\Component\Security\Core\Util\StringUtils;
2425

2526
/**
2627
* Concrete implementation of the RememberMeServicesInterface which needs
@@ -93,7 +94,7 @@ protected function processAutoLoginCookie(array $cookieParts, Request $request)
9394
list($series, $tokenValue) = $cookieParts;
9495
$persistentToken = $this->tokenProvider->loadTokenBySeries($series);
9596

96-
if ($persistentToken->getTokenValue() !== $tokenValue) {
97+
if (!StringUtils::equals($persistentToken->getTokenValue(), $tokenValue)) {
9798
throw new CookieTheftException('This token was already used. The account is possibly compromised.');
9899
}
99100

src/Symfony/Component/Security/Http/Tests/Firewall/RememberMeListenerTest.php

+63
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,69 @@ public function testSessionStrategy()
246246
$listener->handle($event);
247247
}
248248

249+
public function testSessionIsMigratedByDefault()
250+
{
251+
list($listener, $tokenStorage, $service, $manager, , $dispatcher, $sessionStrategy) = $this->getListener(false, true, false);
252+
253+
$tokenStorage
254+
->expects($this->once())
255+
->method('getToken')
256+
->will($this->returnValue(null))
257+
;
258+
259+
$token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
260+
$service
261+
->expects($this->once())
262+
->method('autoLogin')
263+
->will($this->returnValue($token))
264+
;
265+
266+
$tokenStorage
267+
->expects($this->once())
268+
->method('setToken')
269+
->with($this->equalTo($token))
270+
;
271+
272+
$manager
273+
->expects($this->once())
274+
->method('authenticate')
275+
->will($this->returnValue($token))
276+
;
277+
278+
$session = $this->getMock('\Symfony\Component\HttpFoundation\Session\SessionInterface');
279+
$session
280+
->expects($this->once())
281+
->method('isStarted')
282+
->will($this->returnValue(true))
283+
;
284+
$session
285+
->expects($this->once())
286+
->method('migrate')
287+
;
288+
289+
$request = $this->getMock('\Symfony\Component\HttpFoundation\Request');
290+
$request
291+
->expects($this->any())
292+
->method('hasSession')
293+
->will($this->returnValue(true))
294+
;
295+
296+
$request
297+
->expects($this->any())
298+
->method('getSession')
299+
->will($this->returnValue($session))
300+
;
301+
302+
$event = $this->getGetResponseEvent();
303+
$event
304+
->expects($this->once())
305+
->method('getRequest')
306+
->will($this->returnValue($request))
307+
;
308+
309+
$listener->handle($event);
310+
}
311+
249312
public function testOnCoreSecurityInteractiveLoginEventIsDispatchedIfDispatcherIsPresent()
250313
{
251314
list($listener, $tokenStorage, $service, $manager, , $dispatcher) = $this->getListener(true);

0 commit comments

Comments
 (0)