[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#1030851: bullseye-pu: package symfony/4.4.19+dfsg-2+deb11u2



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


Reply to: