Package: release.debian.org Severity: normal Tags: bullseye User: release.debian....@packages.debian.org Usertags: pu X-Debbugs-Cc: symf...@packages.debian.org, Debian PHP PEAR Maintainers <pkg-php-p...@lists.alioth.debian.org> Control: affects -1 + src:symfony
[ Reason ] I’ve been asked the security team to provide those fixes for the upcoming 11.7 point release after their review. [ Impact ] Two CVEs have been assigned to Symfony, the version currently in unstable and bookworm ships the fixes, the attached debdiff is a proposal for Bullseye. https://symfony.com/blog/cve-2022-24894-prevent-storing-cookie-headers-in-httpcache https://symfony.com/blog/cve-2022-24895-csrf-token-fixation [ Tests ] I didn’t test it thoroughly (I doubt to have much time for at least another week), but it passes [ Checklist ] [x] *all* changes are documented in the d/changelog [x] I reviewed all changes and I approve them [x] attach debdiff against the package in (old)stable [x] the issue is verified as fixed in unstable Regards taffit
diff -Nru symfony-4.4.19+dfsg/debian/changelog symfony-4.4.19+dfsg/debian/changelog --- symfony-4.4.19+dfsg/debian/changelog 2021-11-24 11:07:00.000000000 +0100 +++ symfony-4.4.19+dfsg/debian/changelog 2023-02-01 19:38:41.000000000 +0100 @@ -1,3 +1,13 @@ +symfony (4.4.19+dfsg-2+deb11u2) bullseye; urgency=medium + + * Backport security fixes from Symfony 4.4.50 + - [HttpKernel] Remove private headers before storing responses with + HttpCache [CVE-2022-24894] + - [Security/Http] Remove CSRF tokens from storage on successful login + [CVE-2022-24895] + + -- David Prévot <taf...@debian.org> Wed, 01 Feb 2023 19:38:41 +0100 + symfony (4.4.19+dfsg-2+deb11u1) bullseye; urgency=medium * Prevent CSV injection via formulas [CVE-2021-41270] diff -Nru symfony-4.4.19+dfsg/debian/patches/HttpKernel-Remove-private-headers-before-storing-response.patch symfony-4.4.19+dfsg/debian/patches/HttpKernel-Remove-private-headers-before-storing-response.patch --- symfony-4.4.19+dfsg/debian/patches/HttpKernel-Remove-private-headers-before-storing-response.patch 1970-01-01 01:00:00.000000000 +0100 +++ symfony-4.4.19+dfsg/debian/patches/HttpKernel-Remove-private-headers-before-storing-response.patch 2023-02-01 19:38:41.000000000 +0100 @@ -0,0 +1,92 @@ +From: Nicolas Grekas <nicolas.gre...@gmail.com> +Date: Thu, 3 Mar 2022 11:39:01 +0100 +Subject: [HttpKernel] Remove private headers before storing responses with + HttpCache [CVE-2022-24894] + +Origin: upstream, https://github.com/symfony/symfony/commit/d2f6322af9444ac5cd1ef3ac6f280dbef7f9d1fb +--- + src/Symfony/Component/HttpKernel/HttpCache/Store.php | 20 +++++++++++++++++--- + .../HttpKernel/Tests/HttpCache/StoreTest.php | 13 +++++++++++++ + 2 files changed, 30 insertions(+), 3 deletions(-) + +diff --git a/src/Symfony/Component/HttpKernel/HttpCache/Store.php b/src/Symfony/Component/HttpKernel/HttpCache/Store.php +index 3b69289..6451b9e 100644 +--- a/src/Symfony/Component/HttpKernel/HttpCache/Store.php ++++ b/src/Symfony/Component/HttpKernel/HttpCache/Store.php +@@ -26,19 +26,29 @@ class Store implements StoreInterface + { + protected $root; + private $keyCache; +- private $locks; ++ private $locks = []; ++ private $options; + + /** ++ * Constructor. ++ * ++ * The available options are: ++ * ++ * * private_headers Set of response headers that should not be stored ++ * when a response is cached. (default: Set-Cookie) ++ * + * @throws \RuntimeException + */ +- public function __construct(string $root) ++ public function __construct(string $root, array $options = []) + { + $this->root = $root; + if (!file_exists($this->root) && !@mkdir($this->root, 0777, true) && !is_dir($this->root)) { + throw new \RuntimeException(sprintf('Unable to create the store directory (%s).', $this->root)); + } + $this->keyCache = new \SplObjectStorage(); +- $this->locks = []; ++ $this->options = array_merge([ ++ 'private_headers' => ['Set-Cookie'], ++ ], $options); + } + + /** +@@ -215,6 +225,10 @@ class Store implements StoreInterface + $headers = $this->persistResponse($response); + unset($headers['age']); + ++ foreach ($this->options['private_headers'] as $h) { ++ unset($headers[strtolower($h)]); ++ } ++ + array_unshift($entries, [$storedEnv, $headers]); + + if (!$this->save($key, serialize($entries))) { +diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php +index da1f649..239361b 100644 +--- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php ++++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php +@@ -12,8 +12,10 @@ + namespace Symfony\Component\HttpKernel\Tests\HttpCache; + + use PHPUnit\Framework\TestCase; ++use Symfony\Component\HttpFoundation\Cookie; + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\HttpFoundation\Response; ++use Symfony\Component\HttpKernel\HttpCache\HttpCache; + use Symfony\Component\HttpKernel\HttpCache\Store; + + class StoreTest extends TestCase +@@ -317,6 +319,17 @@ class StoreTest extends TestCase + $this->assertEmpty($this->getStoreMetadata($requestHttps)); + } + ++ public function testDoesNotStorePrivateHeaders() ++ { ++ $request = Request::create('https://example.com/foo'); ++ $response = new Response('foo'); ++ $response->headers->setCookie(Cookie::fromString('foo=bar')); ++ ++ $this->store->write($request, $response); ++ $this->assertArrayNotHasKey('set-cookie', $this->getStoreMetadata($request)[0][1]); ++ $this->assertNotEmpty($response->headers->getCookies()); ++ } ++ + protected function storeSimpleEntry($path = null, $headers = []) + { + if (null === $path) { diff -Nru symfony-4.4.19+dfsg/debian/patches/Security-Http-Remove-CSRF-tokens-from-storage-on-successf.patch symfony-4.4.19+dfsg/debian/patches/Security-Http-Remove-CSRF-tokens-from-storage-on-successf.patch --- symfony-4.4.19+dfsg/debian/patches/Security-Http-Remove-CSRF-tokens-from-storage-on-successf.patch 1970-01-01 01:00:00.000000000 +0100 +++ symfony-4.4.19+dfsg/debian/patches/Security-Http-Remove-CSRF-tokens-from-storage-on-successf.patch 2023-02-01 19:38:41.000000000 +0100 @@ -0,0 +1,171 @@ +From: Nicolas Grekas <nicolas.gre...@gmail.com> +Date: Mon, 23 Jan 2023 19:43:46 +0100 +Subject: [Security/Http] Remove CSRF tokens from storage on successful login + [CVE-2022-24895] + +Origin: backport, https://github.com/symfony/symfony/commit/c75c5699f02da5ebb92ca6424aeb0e7cac5703a4 +--- + .../Bundle/SecurityBundle/Resources/config/security.xml | 1 + + .../SecurityBundle/Tests/Functional/CsrfFormLoginTest.php | 6 ++++++ + .../Bundle/SecurityBundle/Tests/Functional/LogoutTest.php | 4 +--- + src/Symfony/Bundle/SecurityBundle/composer.json | 2 +- + .../Http/Session/SessionAuthenticationStrategy.php | 14 +++++++++++--- + .../Tests/Session/SessionAuthenticationStrategyTest.php | 13 +++++++++++++ + 6 files changed, 33 insertions(+), 7 deletions(-) + +diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml +index 3491383..eabe5e5 100644 +--- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml ++++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml +@@ -63,6 +63,7 @@ + + <service id="security.authentication.session_strategy" class="Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy"> + <argument>%security.authentication.session_strategy.strategy%</argument> ++ <argument type="service" id="security.csrf.token_storage" on-invalid="ignore" /> + </service> + <service id="Symfony\Component\Security\Http\Session\SessionAuthenticationStrategyInterface" alias="security.authentication.session_strategy" /> + +diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/CsrfFormLoginTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/CsrfFormLoginTest.php +index 1a672d7..08ea67a 100644 +--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/CsrfFormLoginTest.php ++++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/CsrfFormLoginTest.php +@@ -19,12 +19,15 @@ class CsrfFormLoginTest extends AbstractWebTestCase + public function testFormLoginAndLogoutWithCsrfTokens($config) + { + $client = $this->createClient(['test_case' => 'CsrfFormLogin', 'root_config' => $config]); ++ static::$container->get('security.csrf.token_storage')->setToken('foo', 'bar'); + + $form = $client->request('GET', '/login')->selectButton('login')->form(); + $form['user_login[username]'] = 'johannes'; + $form['user_login[password]'] = 'test'; + $client->submit($form); + ++ $this->assertFalse(static::$container->get('security.csrf.token_storage')->hasToken('foo')); ++ + $this->assertRedirect($client->getResponse(), '/profile'); + + $crawler = $client->followRedirect(); +@@ -48,11 +51,14 @@ class CsrfFormLoginTest extends AbstractWebTestCase + public function testFormLoginWithInvalidCsrfToken($config) + { + $client = $this->createClient(['test_case' => 'CsrfFormLogin', 'root_config' => $config]); ++ static::$container->get('security.csrf.token_storage')->setToken('foo', 'bar'); + + $form = $client->request('GET', '/login')->selectButton('login')->form(); + $form['user_login[_token]'] = ''; + $client->submit($form); + ++ $this->assertTrue(static::$container->get('security.csrf.token_storage')->hasToken('foo')); ++ + $this->assertRedirect($client->getResponse(), '/login'); + + $text = $client->followRedirect()->text(null, true); +diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LogoutTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LogoutTest.php +index cb7868f..465027f 100644 +--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LogoutTest.php ++++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/LogoutTest.php +@@ -36,15 +36,13 @@ class LogoutTest extends AbstractWebTestCase + public function testCsrfTokensAreClearedOnLogout() + { + $client = $this->createClient(['test_case' => 'LogoutWithoutSessionInvalidation', 'root_config' => 'config.yml']); +- static::$container->get('security.csrf.token_storage')->setToken('foo', 'bar'); + + $client->request('POST', '/login', [ + '_username' => 'johannes', + '_password' => 'test', + ]); + +- $this->assertTrue(static::$container->get('security.csrf.token_storage')->hasToken('foo')); +- $this->assertSame('bar', static::$container->get('security.csrf.token_storage')->getToken('foo')); ++ static::$container->get('security.csrf.token_storage')->setToken('foo', 'bar'); + + $client->request('GET', '/logout'); + +diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json +index 872ef66..6627cdb 100644 +--- a/src/Symfony/Bundle/SecurityBundle/composer.json ++++ b/src/Symfony/Bundle/SecurityBundle/composer.json +@@ -24,7 +24,7 @@ + "symfony/security-core": "^4.4", + "symfony/security-csrf": "^4.2|^5.0", + "symfony/security-guard": "^4.2|^5.0", +- "symfony/security-http": "^4.4.5" ++ "symfony/security-http": "^4.4.50" + }, + "require-dev": { + "doctrine/doctrine-bundle": "^1.5|^2.0", +diff --git a/src/Symfony/Component/Security/Http/Session/SessionAuthenticationStrategy.php b/src/Symfony/Component/Security/Http/Session/SessionAuthenticationStrategy.php +index a4bb888..7369105 100644 +--- a/src/Symfony/Component/Security/Http/Session/SessionAuthenticationStrategy.php ++++ b/src/Symfony/Component/Security/Http/Session/SessionAuthenticationStrategy.php +@@ -13,6 +13,7 @@ namespace Symfony\Component\Security\Http\Session; + + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; ++use Symfony\Component\Security\Csrf\TokenStorage\ClearableTokenStorageInterface; + + /** + * The default session strategy implementation. +@@ -31,10 +32,15 @@ class SessionAuthenticationStrategy implements SessionAuthenticationStrategyInte + public const INVALIDATE = 'invalidate'; + + private $strategy; ++ private $csrfTokenStorage = null; + +- public function __construct(string $strategy) ++ public function __construct(string $strategy, ClearableTokenStorageInterface $csrfTokenStorage = null) + { + $this->strategy = $strategy; ++ ++ if (self::MIGRATE === $strategy) { ++ $this->csrfTokenStorage = $csrfTokenStorage; ++ } + } + + /** +@@ -47,10 +53,12 @@ class SessionAuthenticationStrategy implements SessionAuthenticationStrategyInte + return; + + case self::MIGRATE: +- // Note: this logic is duplicated in several authentication listeners +- // until Symfony 5.0 due to a security fix with BC compat + $request->getSession()->migrate(true); + ++ if ($this->csrfTokenStorage) { ++ $this->csrfTokenStorage->clear(); ++ } ++ + return; + + case self::INVALIDATE: +diff --git a/src/Symfony/Component/Security/Http/Tests/Session/SessionAuthenticationStrategyTest.php b/src/Symfony/Component/Security/Http/Tests/Session/SessionAuthenticationStrategyTest.php +index 94ff922..66550a2 100644 +--- a/src/Symfony/Component/Security/Http/Tests/Session/SessionAuthenticationStrategyTest.php ++++ b/src/Symfony/Component/Security/Http/Tests/Session/SessionAuthenticationStrategyTest.php +@@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase; + use Symfony\Component\HttpFoundation\Request; + use Symfony\Component\HttpFoundation\Session\SessionInterface; + use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; ++use Symfony\Component\Security\Csrf\TokenStorage\ClearableTokenStorageInterface; + use Symfony\Component\Security\Http\Session\SessionAuthenticationStrategy; + + class SessionAuthenticationStrategyTest extends TestCase +@@ -57,6 +58,18 @@ class SessionAuthenticationStrategyTest extends TestCase + $strategy->onAuthentication($this->getRequest($session), $this->getToken()); + } + ++ public function testCsrfTokensAreCleared() ++ { ++ $session = $this->createMock(SessionInterface::class); ++ $session->expects($this->once())->method('migrate')->with($this->equalTo(true)); ++ ++ $csrfStorage = $this->createMock(ClearableTokenStorageInterface::class); ++ $csrfStorage->expects($this->once())->method('clear'); ++ ++ $strategy = new SessionAuthenticationStrategy(SessionAuthenticationStrategy::MIGRATE, $csrfStorage); ++ $strategy->onAuthentication($this->getRequest($session), $this->createMock(TokenInterface::class)); ++ } ++ + private function getRequest($session = null) + { + $request = $this->createMock(Request::class); diff -Nru symfony-4.4.19+dfsg/debian/patches/series symfony-4.4.19+dfsg/debian/patches/series --- symfony-4.4.19+dfsg/debian/patches/series 2021-11-24 11:07:00.000000000 +0100 +++ symfony-4.4.19+dfsg/debian/patches/series 2023-02-01 19:38:41.000000000 +0100 @@ -20,3 +20,5 @@ HttpClient-group-network-for-test-failing-without-vulcain.patch Merge-branch-3.4-into-4.4.patch Use-single-quote-to-escape-formulas.patch +HttpKernel-Remove-private-headers-before-storing-response.patch +Security-Http-Remove-CSRF-tokens-from-storage-on-successf.patch
signature.asc
Description: PGP signature