Merge branch '2.3' into 2.7

* 2.3:
  migrate session after remember me authentication
  prevent timing attacks in digest auth listener
  mitigate CSRF timing attack vulnerability
  fix potential timing attack issue
This commit is contained in:
Fabien Potencier 2015-11-23 11:34:14 +01:00
commit 5edc71e2fc
5 changed files with 83 additions and 5 deletions

View File

@ -11,6 +11,8 @@
namespace Symfony\Component\Form\Extension\Csrf\CsrfProvider;
use Symfony\Component\Security\Core\Util\StringUtils;
@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);
/**
@ -61,7 +63,17 @@ class DefaultCsrfProvider implements CsrfProviderInterface
*/
public function isCsrfTokenValid($intention, $token)
{
return $token === $this->generateCsrfToken($intention);
$expectedToken = $this->generateCsrfToken($intention);
if (function_exists('hash_equals')) {
return hash_equals($expectedToken, $token);
}
if (class_exists('Symfony\Component\Security\Core\Util\StringUtils')) {
return StringUtils::equals($expectedToken, $token);
}
return $token === $expectedToken;
}
/**

View File

@ -12,6 +12,7 @@
namespace Symfony\Component\Security\Http\Firewall;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Util\StringUtils;
use Symfony\Component\Security\Http\EntryPoint\DigestAuthenticationEntryPoint;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
@ -99,7 +100,7 @@ class DigestAuthenticationListener implements ListenerInterface
return;
}
if ($serverDigestMd5 !== $digestAuth->getResponse()) {
if (!StringUtils::equals($serverDigestMd5, $digestAuth->getResponse())) {
if (null !== $this->logger) {
$this->logger->debug('Unexpected response from the DigestAuth received; is the header returning a clear text passwords?', array('expected' => $serverDigestMd5, 'received' => $digestAuth->getResponse()));
}

View File

@ -21,6 +21,7 @@ use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
use Symfony\Component\Security\Http\SecurityEvents;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface;
use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy;
/**
* RememberMeListener implements authentication capabilities via a cookie.
@ -56,7 +57,7 @@ class RememberMeListener implements ListenerInterface
$this->logger = $logger;
$this->dispatcher = $dispatcher;
$this->catchExceptions = $catchExceptions;
$this->sessionStrategy = $sessionStrategy;
$this->sessionStrategy = null === $sessionStrategy ? new SessionAuthenticationStrategy(SessionAuthenticationStrategy::MIGRATE) : $sessionStrategy;
}
/**
@ -77,7 +78,7 @@ class RememberMeListener implements ListenerInterface
try {
$token = $this->authenticationManager->authenticate($token);
if (null !== $this->sessionStrategy && $request->hasSession() && $request->getSession()->isStarted()) {
if ($request->hasSession() && $request->getSession()->isStarted()) {
$this->sessionStrategy->onAuthentication($request, $token);
}
$this->tokenStorage->setToken($token);

View File

@ -21,6 +21,7 @@ use Symfony\Component\Security\Core\Authentication\RememberMe\PersistentToken;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Util\SecureRandomInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Security\Core\Util\StringUtils;
/**
* Concrete implementation of the RememberMeServicesInterface which needs
@ -90,7 +91,7 @@ class PersistentTokenBasedRememberMeServices extends AbstractRememberMeServices
list($series, $tokenValue) = $cookieParts;
$persistentToken = $this->tokenProvider->loadTokenBySeries($series);
if ($persistentToken->getTokenValue() !== $tokenValue) {
if (!StringUtils::equals($persistentToken->getTokenValue(), $tokenValue)) {
throw new CookieTheftException('This token was already used. The account is possibly compromised.');
}

View File

@ -246,6 +246,69 @@ class RememberMeListenerTest extends \PHPUnit_Framework_TestCase
$listener->handle($event);
}
public function testSessionIsMigratedByDefault()
{
list($listener, $tokenStorage, $service, $manager, , $dispatcher, $sessionStrategy) = $this->getListener(false, true, false);
$tokenStorage
->expects($this->once())
->method('getToken')
->will($this->returnValue(null))
;
$token = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\TokenInterface');
$service
->expects($this->once())
->method('autoLogin')
->will($this->returnValue($token))
;
$tokenStorage
->expects($this->once())
->method('setToken')
->with($this->equalTo($token))
;
$manager
->expects($this->once())
->method('authenticate')
->will($this->returnValue($token))
;
$session = $this->getMock('\Symfony\Component\HttpFoundation\Session\SessionInterface');
$session
->expects($this->once())
->method('isStarted')
->will($this->returnValue(true))
;
$session
->expects($this->once())
->method('migrate')
;
$request = $this->getMock('\Symfony\Component\HttpFoundation\Request');
$request
->expects($this->any())
->method('hasSession')
->will($this->returnValue(true))
;
$request
->expects($this->any())
->method('getSession')
->will($this->returnValue($session))
;
$event = $this->getGetResponseEvent();
$event
->expects($this->once())
->method('getRequest')
->will($this->returnValue($request))
;
$listener->handle($event);
}
public function testOnCoreSecurityInteractiveLoginEventIsDispatchedIfDispatcherIsPresent()
{
list($listener, $tokenStorage, $service, $manager, , $dispatcher) = $this->getListener(true);