diff --git a/app/Config/App.php b/app/Config/App.php index 21271622fb75..ffe0c6c8c67e 100644 --- a/app/Config/App.php +++ b/app/Config/App.php @@ -237,12 +237,14 @@ class App extends BaseConfig | recommended CSRF protection be enabled. | | CSRFTokenName = The token name + | CSRFHeaderName = The header name | CSRFCookieName = The cookie name | CSRFExpire = The number in seconds the token should expire. | CSRFRegenerate = Regenerate token on every submission | CSRFRedirect = Redirect to previous page with error on failure */ public $CSRFTokenName = 'csrf_test_name'; + public $CSRFHeaderName = 'X-CSRF-TOKEN'; public $CSRFCookieName = 'csrf_cookie_name'; public $CSRFExpire = 7200; public $CSRFRegenerate = true; diff --git a/system/Security/Security.php b/system/Security/Security.php index a53525cb545d..cc2b2619ebde 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -75,6 +75,15 @@ class Security */ protected $CSRFTokenName = 'CSRFToken'; + /** + * CSRF Header name + * + * Token name for Cross Site Request Forgery protection cookie. + * + * @var string + */ + protected $CSRFHeaderName = 'CSRFToken'; + /** * CSRF Cookie name * @@ -171,6 +180,7 @@ public function __construct($config) // Store our CSRF-related settings $this->CSRFExpire = $config->CSRFExpire; $this->CSRFTokenName = $config->CSRFTokenName; + $this->CSRFHeaderName = $config->CSRFHeaderName; $this->CSRFCookieName = $config->CSRFCookieName; $this->CSRFRegenerate = $config->CSRFRegenerate; @@ -206,12 +216,14 @@ public function CSRFVerify(RequestInterface $request) { return $this->CSRFSetCookie($request); } - - // Do the token exist in _POST or php://input (json) data? - $CSRFTokenValue = $_POST[$this->CSRFTokenName] ?? - (!empty($input = file_get_contents('php://input')) && !empty($json = json_decode($input)) && json_last_error() === JSON_ERROR_NONE ? - ($json->{$this->CSRFTokenName} ?? null) : - null); + + // Do the tokens exist in _POST, HEADER or optionally php:://input - json data + $CSRFTokenValue = $_POST[$this->CSRFTokenName] ?? + (!is_null($request->getHeader($this->CSRFHeaderName)) && !empty($request->getHeader($this->CSRFHeaderName)->getValue()) ? + $request->getHeader($this->CSRFHeaderName)->getValue() : + (!empty($request->getBody()) && !empty($json = json_decode($request->getBody())) && json_last_error() === JSON_ERROR_NONE ? + ($json->{$this->CSRFTokenName} ?? null) : + null)); // Do the tokens exist in both the _POST/POSTed JSON and _COOKIE arrays? if (! isset($CSRFTokenValue, $_COOKIE[$this->CSRFCookieName]) || $CSRFTokenValue !== $_COOKIE[$this->CSRFCookieName] diff --git a/tests/_support/Config/MockAppConfig.php b/tests/_support/Config/MockAppConfig.php index 554e2ddf1b5d..23eef138e6cb 100644 --- a/tests/_support/Config/MockAppConfig.php +++ b/tests/_support/Config/MockAppConfig.php @@ -16,6 +16,7 @@ class MockAppConfig public $CSRFProtection = false; public $CSRFTokenName = 'csrf_test_name'; + public $CSRFHeaderName = 'X-CSRF-TOKEN'; public $CSRFCookieName = 'csrf_cookie_name'; public $CSRFExpire = 7200; public $CSRFRegenerate = true;