CVE-2021-32693 (published 2021-06-17T23:15Z)

Symfony is a PHP framework for web and console applications and a set of reusable PHP components. A vulnerability related to firewall authentication is in Symfony starting with version 5.3.0 and prior to 5.3.2. When an application defines multiple firewalls, the token authenticated by one of the firewalls was available for all other firewalls. This could be abused when the application defines different providers for each part of the application, in such a situation, a user authenticated on a part of the application could be considered authenticated on the rest of the application. Starting in version 5.3.2, a patch ensures that the authenticated token is only available for the firewall that generates it.

Severity: MEDIUM
CVSS v2 base score: 6.5 (AV:N/AC:L/Au:S/C:P/I:P/A:P)
CVSS v3 base score: 8.8, HIGH (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-287
cwe_name: Improper Authentication
description: When an actor claims to have a given identity, the product does not prove or insufficiently proves that the claim is correct.
extended_description: 
            
			
         
         

Fix information:
repo_url: https://github.com/symfony/symfony
commit_details: repo_url: https://github.com/symfony/symfony
author: Wouter de Jong
author_date: 2021-06-03 16:11:19+02:00
msg: Only trigger for the correct firewall in ContextListener::onKernelResponse()
repository: repo_url: https://github.com/symfony/symfony
repo_name: symfony/symfony
description: The Symfony PHP framework
repo_language: PHP
owner: symfony
file_changes: filename: AuthenticatorTest.php
change_type: ModificationType.MODIFY
diff: @@ -87,4 +87,17 @@ class AuthenticatorTest extends AbstractWebTestCase
         yield ['jane@example.org', 'main'];
         yield ['john@example.org', 'custom'];
     }
+
+    public function testMultipleFirewalls()
+    {
+        $client = $this->createClient(['test_case' => 'Authenticator', 'root_config' => 'multiple_firewalls.yml']);
+
+        $client->request('POST', '/firewall1/login', [
+            '_username' => 'jane@example.org',
+            '_password' => 'test',
+        ]);
+
+        $client->request('GET', '/firewall2/profile');
+        $this->assertResponseRedirects('http://localhost/login');
+    }
 }

programming_language: PHP
filename: multiple_firewalls.yml
change_type: ModificationType.ADD
diff: @@ -0,0 +1,17 @@
+imports:
+- { resource: ./config.yml }
+- { resource: ./security.yml }
+
+security:
+    enable_authenticator_manager: true
+    firewalls:
+        firewall1:
+            pattern: /firewall1
+            provider: in_memory
+            form_login:
+                check_path: /firewall1/login
+        firewall2:
+            pattern: /firewall2
+            provider: in_memory2
+            form_login:
+                check_path: /firewall2/login

programming_language: Markdown
filename: routing.yml
change_type: ModificationType.MODIFY
diff: @@ -18,3 +18,11 @@ security_main_profile:
 security_custom_profile:
     path:     /custom/user_profile
     defaults: { _controller: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AuthenticatorBundle\SecurityController::profileAction }
+
+firewall1_login:
+    path: /firewall1/login
+
+firewall2_profile:
+    path: /firewall2/profile
+    defaults:
+        _controller: Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\AuthenticatorBundle\ProfileController

programming_language: Batchfile
filename: composer.json
change_type: ModificationType.MODIFY
diff: @@ -29,7 +29,7 @@
         "symfony/security-core": "^5.3",
         "symfony/security-csrf": "^4.4|^5.0",
         "symfony/security-guard": "^5.3",
-        "symfony/security-http": "^5.3"
+        "symfony/security-http": "^5.3.2"
     },
     "require-dev": {
         "doctrine/annotations": "^1.10.4",

programming_language: TypeScript
filename: ContextListener.php
change_type: ModificationType.MODIFY
diff: @@ -95,7 +95,7 @@ class ContextListener extends AbstractListener
         $request = $event->getRequest();
         $session = $request->hasPreviousSession() && $request->hasSession() ? $request->getSession() : null;
 
-        $request->attributes->set('_security_firewall_run', true);
+        $request->attributes->set('_security_firewall_run', $this->sessionKey);
 
         if (null !== $session) {
             $usageIndexValue = $session instanceof Session ? $usageIndexReference = &$session->getUsageIndex() : 0;
@@ -169,7 +169,7 @@ class ContextListener extends AbstractListener
 
         $request = $event->getRequest();
 
-        if (!$request->hasSession() || !$request->attributes->get('_security_firewall_run', false)) {
+        if (!$request->hasSession() || $request->attributes->get('_security_firewall_run') !== $this->sessionKey) {
             return;
         }
 

programming_language: PHP
filename: ContextListenerTest.php
change_type: ModificationType.MODIFY
diff: @@ -106,7 +106,7 @@ class ContextListenerTest extends TestCase
         $tokenStorage = new TokenStorage();
         $tokenStorage->setToken(new UsernamePasswordToken('test1', 'pass1', 'phpunit'));
         $request = new Request();
-        $request->attributes->set('_security_firewall_run', true);
+        $request->attributes->set('_security_firewall_run', '_security_session');
         $session = new Session(new MockArraySessionStorage());
         $request->setSession($session);
 
@@ -212,7 +212,7 @@ class ContextListenerTest extends TestCase
         $listener = new ContextListener($tokenStorage, [], 'key123', null, $dispatcher);
 
         $request = new Request();
-        $request->attributes->set('_security_firewall_run', true);
+        $request->attributes->set('_security_firewall_run', '_security_key123');
         $request->setSession($session);
 
         $event = new ResponseEvent($this->createMock(HttpKernelInterface::class), $request, HttpKernelInterface::MAIN_REQUEST, new Response());
@@ -370,7 +370,7 @@ class ContextListenerTest extends TestCase
     {
         $session = new Session(new MockArraySessionStorage());
         $request = new Request();
-        $request->attributes->set('_security_firewall_run', true);
+        $request->attributes->set('_security_firewall_run', '_security_session');
         $request->setSession($session);
         $requestStack = new RequestStack();
         $requestStack->push($request);

programming_language: PHP
repo_url: https://github.com/symfony/security-http
commit_details: repo_url: https://github.com/symfony/security-http
author: Nicolas Grekas
author_date: 2021-06-17 15:35:32+02:00
msg: security #cve-2021-32693 [SecurityHttp] Fix "Authentication granted with multiple firewalls" (wouterj)

This PR was merged into the 5.3 branch.
repository: repo_url: https://github.com/symfony/security-http
repo_name: symfony/security-http
description: Symfony Security Component - HTTP Integration
repo_language: PHP
owner: symfony