Browse Source

Merge pull request #12527 from garas/malformed_encrypted_cookies

Consistent result value for malformed encrypted cookies
Mark Story 7 years ago
parent
commit
fc95e24f24

+ 16 - 1
src/Utility/CookieCryptTrait.php

@@ -128,7 +128,18 @@ trait CookieCryptTrait
         }
         $this->_checkCipher($encrypt);
         $prefix = 'Q2FrZQ==.';
-        $value = base64_decode(substr($value, strlen($prefix)));
+        $prefixLength = strlen($prefix);
+
+        if (strncmp($value, $prefix, $prefixLength) !== 0) {
+            return '';
+        }
+
+        $value = base64_decode(substr($value, $prefixLength), true);
+
+        if ($value === false || $value === '') {
+            return '';
+        }
+
         if ($key === null) {
             $key = $this->_getCookieEncryptionKey();
         }
@@ -139,6 +150,10 @@ trait CookieCryptTrait
             $value = Security::decrypt($value, $key);
         }
 
+        if ($value === false) {
+            return '';
+        }
+
         return $this->_explode($value);
     }
 

+ 34 - 0
tests/TestCase/Controller/Component/CookieComponentTest.php

@@ -650,6 +650,40 @@ class CookieComponentTest extends TestCase
     }
 
     /**
+     * testReadingMalformedEncryptedCookies
+     *
+     * @return void
+     */
+    public function testReadingMalformedEncryptedCookies()
+    {
+        $this->Cookie->configKey('Encrypted_empty', 'encryption', 'aes');
+        $this->Cookie->configKey('Encrypted_wrong_prefix', 'encryption', 'aes');
+        $this->Cookie->configKey('Encrypted_altered', 'encryption', 'aes');
+        $this->Cookie->configKey('Encrypted_invalid_chars', 'encryption', 'aes');
+
+        $encrypted = $this->_encrypt('secret data', 'aes');
+
+        $this->Controller->request = $this->request->withCookieParams([
+            'Encrypted_empty' => '',
+            'Encrypted_wrong_prefix' => substr_replace($encrypted, 'foo', 0, 3),
+            'Encrypted_altered' => str_replace('M', 'A', $encrypted),
+            'Encrypted_invalid_chars' => str_replace('M', 'M#', $encrypted),
+        ]);
+
+        $data = $this->Cookie->read('Encrypted_empty');
+        $this->assertEquals('', $data);
+
+        $data = $this->Cookie->read('Encrypted_wrong_prefix');
+        $this->assertEquals('', $data);
+
+        $data = $this->Cookie->read('Encrypted_altered');
+        $this->assertEquals('', $data);
+
+        $data = $this->Cookie->read('Encrypted_invalid_chars');
+        $this->assertEquals('', $data);
+    }
+
+    /**
      * Test Reading legacy cookie values.
      *
      * @return void

+ 43 - 0
tests/TestCase/Http/Middleware/EncryptedCookieMiddlewareTest.php

@@ -74,6 +74,49 @@ class EncryptedCookieMiddlewareTest extends TestCase
     }
 
     /**
+     * Test decoding malformed cookies
+     *
+     * @dataProvider malformedCookies
+     * @param string $cookie
+     * @return void
+     */
+    public function testDecodeMalformedCookies($cookie)
+    {
+        $request = new ServerRequest(['url' => '/cookies/nom']);
+        $request = $request->withCookieParams(['secret' => $cookie]);
+
+        $response = new Response();
+        $next = function ($req, $res) {
+            $this->assertSame('', $req->getCookie('secret'));
+
+            return $res;
+        };
+        $middleware = new EncryptedCookieMiddleware(
+            ['secret'],
+            $this->_getCookieEncryptionKey(),
+            'aes'
+        );
+        $response = $middleware($request, $response, $next);
+    }
+
+    /**
+     * Data provider for malformed cookies.
+     *
+     * @return array
+     */
+    public function malformedCookies()
+    {
+        $encrypted = $this->_encrypt('secret data', 'aes');
+
+        return [
+            'empty' => [''],
+            'wrong prefix' => [substr_replace($encrypted, 'foo', 0, 3)],
+            'altered' => [str_replace('M', 'A', $encrypted)],
+            'invalid chars' => [str_replace('M', 'M#', $encrypted)],
+        ];
+    }
+
+    /**
      * Test encoding cookies in the set-cookie header.
      *
      * @return void