Package: release.debian.org Severity: normal Tags: bullseye User: release.debian.org@packages.debian.org Usertags: pu X-Debbugs-Cc: symfony@packages.debian.org, Debian PHP PEAR Maintainers <pkg-php-pear@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 <taffit@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.grekas@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.grekas@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
Attachment:
signature.asc
Description: PGP signature