Skip to content

Commit 219118a

Browse files
thewilkybarkidnicolas-grekas
authored andcommitted
[Security] Fail gracefully if the security token cannot be unserialized from the session
1 parent 05adcd0 commit 219118a

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

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

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public function handle(GetResponseEvent $event)
7777
return;
7878
}
7979

80-
$token = unserialize($token);
80+
$token = $this->safelyUnserialize($token);
8181

8282
if (null !== $this->logger) {
8383
$this->logger->debug('Read existing security token from the session.', array('key' => $this->sessionKey));
@@ -171,4 +171,36 @@ protected function refreshUser(TokenInterface $token)
171171

172172
throw new \RuntimeException(sprintf('There is no user provider for user "%s".', get_class($user)));
173173
}
174+
175+
private function safelyUnserialize($serializedToken)
176+
{
177+
$eCode = 0x37313bc;
178+
$e = $token = null;
179+
$prevUnserializeHandler = ini_set('unserialize_callback_func', '');
180+
$prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = array()) use (&$prevErrorHandler, $eCode) {
181+
if (E_WARNING === $type && ('Class __PHP_Incomplete_Class has no unserializer' === $msg || 0 === strpos($msg, 'unserialize(): '))) {
182+
throw new \ErrorException($msg, $eCode, $type, $file, $line);
183+
}
184+
185+
return $prevErrorHandler ? $prevErrorHandler($type, $msg, $file, $line, $context) : false;
186+
});
187+
188+
try {
189+
$token = unserialize($serializedToken);
190+
} catch (\Error $e) {
191+
} catch (\Exception $e) {
192+
}
193+
restore_error_handler();
194+
ini_set('unserialize_callback_func', $prevUnserializeHandler);
195+
if ($e) {
196+
if (!$e instanceof \ErrorException || $eCode !== $e->getCode()) {
197+
throw $e;
198+
}
199+
if ($logger) {
200+
$this->logger->warning('Failed to unserialize the security token from the session.', array('key' => $this->sessionKey, 'received' => $serializedToken, 'exception' => $e));
201+
}
202+
}
203+
204+
return $token;
205+
}
174206
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,7 @@ public function testInvalidTokenInSession($token)
169169
public function provideInvalidToken()
170170
{
171171
return array(
172+
array('foo'),
172173
array(serialize(new \__PHP_Incomplete_Class())),
173174
array(serialize(null)),
174175
array(null),

0 commit comments

Comments
 (0)