From ad5d04461e4d805c2c9b9866010926fa61a5843f Mon Sep 17 00:00:00 2001 From: erikkloeze Date: Fri, 10 Apr 2020 11:06:59 +0200 Subject: [PATCH 1/5] Update Controller.php --- system/Controller.php | 60 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/system/Controller.php b/system/Controller.php index 1bb35ae322dd..d35e3794c9f1 100644 --- a/system/Controller.php +++ b/system/Controller.php @@ -212,12 +212,72 @@ protected function validate($rules, array $messages = []): bool $rules = $validation->$rules; } + + // Replace any placeholders (i.e. {id}) in the rules with + // the value found in $data, if exists. + $rules = $this->fillPlaceholders($rules, $this->request->getVar()); return $this->validator ->withRequest($this->request) ->setRules($rules, $messages) ->run(); } + + /** + * Replace any placeholders within the rules with the values that + * match the 'key' of any properties being set. For example, if + * we had the following $data array: + * + * [ 'id' => 13 ] + * + * and the following rule: + * + * 'required|is_unique[users,email,id,{id}]' + * + * The value of {id} would be replaced with the actual id in the form data: + * + * 'required|is_unique[users,email,id,13]' + * + * @param array $rules + * @param array $data + * + * @return array + */ + protected function fillPlaceholders(array $rules, array $data): array + { + $replacements = []; + + foreach ($data as $key => $value) + { + $replacements["{{$key}}"] = $value; + } + + if (! empty($replacements)) + { + foreach ($rules as &$rule) + { + if (is_array($rule)) + { + foreach ($rule as &$row) + { + // Should only be an `errors` array + // which doesn't take placeholders. + if (is_array($row)) + { + continue; + } + + $row = strtr($row, $replacements); + } + continue; + } + + $rule = strtr($rule, $replacements); + } + } + + return $rules; + } //-------------------------------------------------------------------- } From 35cdf1e39773a40ce882286345d93e1a0ae2f927 Mon Sep 17 00:00:00 2001 From: erikkloeze Date: Wed, 27 May 2020 09:07:41 +0200 Subject: [PATCH 2/5] Added SameSite attribute to config file --- app/Config/App.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Config/App.php b/app/Config/App.php index b91c058e951f..9a44b3e4714c 100644 --- a/app/Config/App.php +++ b/app/Config/App.php @@ -239,6 +239,7 @@ class App extends BaseConfig | CSRFTokenName = The token name | CSRFHeaderName = The header name | CSRFCookieName = The cookie name + | CSRFCookieSameSite = The cookie SameSite attribute (none, Lax or Strict) | CSRFExpire = The number in seconds the token should expire. | CSRFRegenerate = Regenerate token on every submission | CSRFRedirect = Redirect to previous page with error on failure @@ -246,6 +247,7 @@ class App extends BaseConfig public $CSRFTokenName = 'csrf_test_name'; public $CSRFHeaderName = 'X-CSRF-TOKEN'; public $CSRFCookieName = 'csrf_cookie_name'; + public $CSRFCookieSameSite = 'strict'; public $CSRFExpire = 7200; public $CSRFRegenerate = true; public $CSRFRedirect = true; From 29d77d1bfb106f9895a147101f1efe11c13749f1 Mon Sep 17 00:00:00 2001 From: erikkloeze Date: Wed, 27 May 2020 09:12:03 +0200 Subject: [PATCH 3/5] Added SameSite attribute to setcookie() Previous to PHP 7.0.3 `setcookie()` lacks an `$options` parameter. SameSite is therefore added to the path parameter. --- system/Security/Security.php | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/system/Security/Security.php b/system/Security/Security.php index 28318d97bfd6..0f9d3225d500 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -93,6 +93,15 @@ class Security * @var string */ protected $CSRFCookieName = 'CSRFToken'; + + /** + * CSRF Cookie SameSite attribute + * + * SameSite attribute for Cross Site Request Forgery protection cookie. + * + * @var string + */ + protected $CSRFCookieSameSite = 'Strict'; /** * CSRF Regenerate @@ -181,6 +190,7 @@ public function __construct($config) // Store our CSRF-related settings $this->CSRFExpire = $config->CSRFExpire; $this->CSRFTokenName = $config->CSRFTokenName; + $this->CSRFCookieSameSite = $config->CSRFCookieSameSite; $this->CSRFHeaderName = $config->CSRFHeaderName; $this->CSRFCookieName = $config->CSRFCookieName; $this->CSRFRegenerate = $config->CSRFRegenerate; @@ -283,9 +293,21 @@ public function CSRFSetCookie(RequestInterface $request) return false; } - setcookie( - $this->CSRFCookieName, $this->CSRFHash, $expire, $this->cookiePath, $this->cookieDomain, $secure_cookie, true // Enforce HTTP only cookie for security - ); + if (PHP_VERSION_ID < 70300) { + setcookie( + $this->CSRFCookieName, $this->CSRFHash, $expire, $this->cookiePath . "; samesite=" . $this->CSRFCookieSameSite, $this->cookieDomain, $secure_cookie, true // Enforce HTTP only cookie for security + ); + } + else { + setcookie($this->CSRFCookieName, $this->CSRFHash, [ + 'expires' => $expire, + 'path' => $this->cookiePath, + 'domain' => $this->cookieDomain, + 'secure' => $secure_cookie, + 'httponly' => true, // Enforce HTTP only cookie for security + 'samesite' => $this->CSRFCookieSameSite, + ]); + } log_message('info', 'CSRF cookie sent'); From 8031b03a4fb8f2be81c3756532937c3cd857477b Mon Sep 17 00:00:00 2001 From: erikkloeze Date: Wed, 27 May 2020 09:19:34 +0200 Subject: [PATCH 4/5] Update Controller.php --- system/Controller.php | 60 ------------------------------------------- 1 file changed, 60 deletions(-) diff --git a/system/Controller.php b/system/Controller.php index d35e3794c9f1..1bb35ae322dd 100644 --- a/system/Controller.php +++ b/system/Controller.php @@ -212,72 +212,12 @@ protected function validate($rules, array $messages = []): bool $rules = $validation->$rules; } - - // Replace any placeholders (i.e. {id}) in the rules with - // the value found in $data, if exists. - $rules = $this->fillPlaceholders($rules, $this->request->getVar()); return $this->validator ->withRequest($this->request) ->setRules($rules, $messages) ->run(); } - - /** - * Replace any placeholders within the rules with the values that - * match the 'key' of any properties being set. For example, if - * we had the following $data array: - * - * [ 'id' => 13 ] - * - * and the following rule: - * - * 'required|is_unique[users,email,id,{id}]' - * - * The value of {id} would be replaced with the actual id in the form data: - * - * 'required|is_unique[users,email,id,13]' - * - * @param array $rules - * @param array $data - * - * @return array - */ - protected function fillPlaceholders(array $rules, array $data): array - { - $replacements = []; - - foreach ($data as $key => $value) - { - $replacements["{{$key}}"] = $value; - } - - if (! empty($replacements)) - { - foreach ($rules as &$rule) - { - if (is_array($rule)) - { - foreach ($rule as &$row) - { - // Should only be an `errors` array - // which doesn't take placeholders. - if (is_array($row)) - { - continue; - } - - $row = strtr($row, $replacements); - } - continue; - } - - $rule = strtr($rule, $replacements); - } - } - - return $rules; - } //-------------------------------------------------------------------- } From fa1299545626f22e5167c4d8d568b4647aee536f Mon Sep 17 00:00:00 2001 From: erikkloeze Date: Wed, 3 Jun 2020 11:43:38 +0200 Subject: [PATCH 5/5] Update App.php SameSite CamelCase description --- app/Config/App.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Config/App.php b/app/Config/App.php index 9a44b3e4714c..4abc441f7d93 100644 --- a/app/Config/App.php +++ b/app/Config/App.php @@ -239,7 +239,7 @@ class App extends BaseConfig | CSRFTokenName = The token name | CSRFHeaderName = The header name | CSRFCookieName = The cookie name - | CSRFCookieSameSite = The cookie SameSite attribute (none, Lax or Strict) + | CSRFCookieSameSite = The cookie SameSite attribute (none, lax or strict) | CSRFExpire = The number in seconds the token should expire. | CSRFRegenerate = Regenerate token on every submission | CSRFRedirect = Redirect to previous page with error on failure