CVE-2015-8379 (published 2016-01-26T19:59Z)

CakePHP 2.x and 3.x before 3.1.5 might allow remote attackers to bypass the CSRF protection mechanism via the _method parameter.

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

Weakness information:
cwe_id: CWE-352
cwe_name: Cross-Site Request Forgery (CSRF)
description: The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request.
extended_description: When a web server is designed to receive a request from a client without any mechanism for verifying that it was intentionally sent, then it might be possible for an attacker to trick a client into making an unintentional request to the web server which will be treated as an authentic request. This can be done via a URL, image load, XMLHttpRequest, etc. and can result in exposure of data or unintended code execution.
         

Fix information:
repo_url: https://github.com/cakephp/cakephp
commit_details: repo_url: https://github.com/cakephp/cakephp
author: Mark Story
author_date: 2015-11-25 22:11:16-05:00
msg: Only allow GET, HEAD, OPTIONS to not have CSRF tokens.

This covers cases where bad guys make up fake HTTP methods to trick CSRF
validation.

Update test cases to not muck about in $_SERVER too.
repository: repo_url: https://github.com/cakephp/cakephp
repo_name: cakephp/cakephp
description: CakePHP: The Rapid Development Framework for PHP - Official Repository
repo_language: PHP
owner: cakephp
file_changes: filename: CsrfComponent.php
change_type: ModificationType.MODIFY
diff: @@ -94,7 +94,7 @@ class CsrfComponent extends Component
         if ($request->is('get') && $cookieData === null) {
             $this->_setCookie($request, $response);
         }
-        if ($request->is(['patch', 'put', 'post', 'delete'])) {
+        if (!$request->is(['head', 'get', 'options'])) {
             $this->_validateToken($request);
             unset($request->data[$this->_config['field']]);
         }

programming_language: PHP
filename: CsrfComponentTest.php
change_type: ModificationType.MODIFY
diff: @@ -61,10 +61,11 @@ class CsrfComponentTest extends TestCase
      */
     public function testSettingCookie()
     {
-        $_SERVER['REQUEST_METHOD'] = 'GET';
-
         $controller = $this->getMock('Cake\Controller\Controller', ['redirect']);
-        $controller->request = new Request(['webroot' => '/dir/']);
+        $controller->request = new Request([
+            'environment' => ['REQUEST_METHOD' => 'GET'],
+            'webroot' => '/dir/',
+        ]);
         $controller->response = new Response();
 
         $event = new Event('Controller.startup', $controller);
@@ -87,7 +88,7 @@ class CsrfComponentTest extends TestCase
     public static function httpMethodProvider()
     {
         return [
-            ['PATCH'], ['PUT'], ['POST'], ['DELETE']
+            ['PATCH'], ['PUT'], ['POST'], ['DELETE'], ['PURGE'], ['INVALIDMETHOD']
         ];
     }
 
@@ -100,11 +101,14 @@ class CsrfComponentTest extends TestCase
      */
     public function testValidTokenInHeader($method)
     {
-        $_SERVER['REQUEST_METHOD'] = $method;
-        $_SERVER['HTTP_X_CSRF_TOKEN'] = 'testing123';
-
         $controller = $this->getMock('Cake\Controller\Controller', ['redirect']);
-        $controller->request = new Request(['cookies' => ['csrfToken' => 'testing123']]);
+        $controller->request = new Request([
+            'environment' => [
+                'REQUEST_METHOD' => $method,
+                'HTTP_X_CSRF_TOKEN' => 'testing123',
+            ],
+            'cookies' => ['csrfToken' => 'testing123']
+        ]);
         $controller->response = new Response();
 
         $event = new Event('Controller.startup', $controller);
@@ -122,11 +126,12 @@ class CsrfComponentTest extends TestCase
      */
     public function testInvalidTokenInHeader($method)
     {
-        $_SERVER['REQUEST_METHOD'] = $method;
-        $_SERVER['HTTP_X_CSRF_TOKEN'] = 'nope';
-
         $controller = $this->getMock('Cake\Controller\Controller', ['redirect']);
         $controller->request = new Request([
+            'environment' => [
+                'REQUEST_METHOD' => $method,
+                'HTTP_X_CSRF_TOKEN' => 'nope',
+            ],
             'cookies' => ['csrfToken' => 'testing123']
         ]);
         $controller->response = new Response();
@@ -144,10 +149,11 @@ class CsrfComponentTest extends TestCase
      */
     public function testValidTokenRequestData($method)
     {
-        $_SERVER['REQUEST_METHOD'] = $method;
-
         $controller = $this->getMock('Cake\Controller\Controller', ['redirect']);
         $controller->request = new Request([
+            'environment' => [
+                'REQUEST_METHOD' => $method,
+            ],
             'post' => ['_csrfToken' => 'testing123'],
             'cookies' => ['csrfToken' => 'testing123']
         ]);
@@ -168,10 +174,11 @@ class CsrfComponentTest extends TestCase
      */
     public function testInvalidTokenRequestData($method)
     {
-        $_SERVER['REQUEST_METHOD'] = $method;
-
         $controller = $this->getMock('Cake\Controller\Controller', ['redirect']);
         $controller->request = new Request([
+            'environment' => [
+                'REQUEST_METHOD' => $method,
+            ],
             'post' => ['_csrfToken' => 'nope'],
             'cookies' => ['csrfToken' => 'testing123']
         ]);
@@ -189,10 +196,11 @@ class CsrfComponentTest extends TestCase
      */
     public function testInvalidTokenRequestDataMissing()
     {
-        $_SERVER['REQUEST_METHOD'] = 'POST';
-
         $controller = $this->getMock('Cake\Controller\Controller', ['redirect']);
         $controller->request = new Request([
+            'environment' => [
+                'REQUEST_METHOD' => 'POST',
+            ],
             'post' => [],
             'cookies' => ['csrfToken' => 'testing123']
         ]);
@@ -211,10 +219,11 @@ class CsrfComponentTest extends TestCase
      */
     public function testInvalidTokenMissingCookie($method)
     {
-        $_SERVER['REQUEST_METHOD'] = $method;
-
         $controller = $this->getMock('Cake\Controller\Controller', ['redirect']);
         $controller->request = new Request([
+            'environment' => [
+                'REQUEST_METHOD' => $method
+            ],
             'post' => ['_csrfToken' => 'could-be-valid'],
             'cookies' => []
         ]);
@@ -232,10 +241,9 @@ class CsrfComponentTest extends TestCase
      */
     public function testCsrfValidationSkipsRequestAction()
     {
-        $_SERVER['REQUEST_METHOD'] = 'POST';
-
         $controller = $this->getMock('Cake\Controller\Controller', ['redirect']);
         $controller->request = new Request([
+            'environment' => ['REQUEST_METHOD' => 'POST'],
             'params' => ['requested' => 1],
             'post' => ['_csrfToken' => 'nope'],
             'cookies' => ['csrfToken' => 'testing123']
@@ -256,10 +264,11 @@ class CsrfComponentTest extends TestCase
      */
     public function testConfigurationCookieCreate()
     {
-        $_SERVER['REQUEST_METHOD'] = 'GET';
-
         $controller = $this->getMock('Cake\Controller\Controller', ['redirect']);
-        $controller->request = new Request(['webroot' => '/dir/']);
+        $controller->request = new Request([
+            'environment' => ['REQUEST_METHOD' => 'GET'],
+            'webroot' => '/dir/'
+        ]);
         $controller->response = new Response();
 
         $component = new CsrfComponent($this->registry, [
@@ -290,10 +299,9 @@ class CsrfComponentTest extends TestCase
      */
     public function testConfigurationValidate()
     {
-        $_SERVER['REQUEST_METHOD'] = 'POST';
-
         $controller = $this->getMock('Cake\Controller\Controller', ['redirect']);
         $controller->request = new Request([
+            'environment' => ['REQUEST_METHOD' => 'POST'],
             'cookies' => ['csrfToken' => 'nope', 'token' => 'yes'],
             'post' => ['_csrfToken' => 'no match', 'token' => 'yes'],
         ]);

programming_language: PHP