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:
commit
5edc71e2fc
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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()));
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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.');
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user