diff --git a/system/blueprints/config/system.yaml b/system/blueprints/config/system.yaml index de390e7fb4..573fe2012f 100644 --- a/system/blueprints/config/system.yaml +++ b/system/blueprints/config/system.yaml @@ -1343,6 +1343,12 @@ form: label: PLUGIN_ADMIN.SESSION_PATH help: PLUGIN_ADMIN.SESSION_PATH_HELP + session.samesite: + type: text + size: small + label: PLUGIN_ADMIN.SESSION_SAMESITE + help: PLUGIN_ADMIN.SESSION_SAMESITE_HELP + session.split: type: toggle label: PLUGIN_ADMIN.SESSION_SPLIT diff --git a/system/config/system.yaml b/system/config/system.yaml index 56f0a2e07c..c8d8b04bc0 100644 --- a/system/config/system.yaml +++ b/system/config/system.yaml @@ -168,6 +168,7 @@ session: uniqueness: path # Should sessions be `path` based or `security.salt` based secure: false # Set session secure. If true, indicates that communication for this cookie must be over an encrypted transmission. Enable this only on sites that run exclusively on HTTPS httponly: true # Set session HTTP only. If true, indicates that cookies should be used only over HTTP, and JavaScript modification is not allowed. + samesite: # Set session SameSite. See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite split: true # Sessions should be independent between site and plugins (such as admin) path: diff --git a/system/src/Grav/Common/Service/SessionServiceProvider.php b/system/src/Grav/Common/Service/SessionServiceProvider.php index 2d4dffbc8f..300d5e0fe4 100644 --- a/system/src/Grav/Common/Service/SessionServiceProvider.php +++ b/system/src/Grav/Common/Service/SessionServiceProvider.php @@ -44,6 +44,7 @@ public function register(Container $container) $cookie_httponly = (bool)$config->get('system.session.httponly', true); $cookie_lifetime = (int)$config->get('system.session.timeout', 1800); $cookie_path = $config->get('system.session.path'); + $cookie_samesite = $config->get('system.session.samesite'); if (null === $cookie_path) { $cookie_path = '/' . trim(Uri::filterPath($uri->rootUrl(false)), '/'); } @@ -95,7 +96,8 @@ public function register(Container $container) 'cookie_path' => $cookie_path, 'cookie_domain' => $cookie_domain, 'cookie_secure' => $cookie_secure, - 'cookie_httponly' => $cookie_httponly + 'cookie_httponly' => $cookie_httponly, + 'cookie_samesite' => $cookie_samesite ] + (array) $config->get('system.session.options'); $session = new Session($options); diff --git a/system/src/Grav/Framework/Session/Session.php b/system/src/Grav/Framework/Session/Session.php index 8f7af7e820..20c41c04a1 100644 --- a/system/src/Grav/Framework/Session/Session.php +++ b/system/src/Grav/Framework/Session/Session.php @@ -140,6 +140,7 @@ public function setOptions(array $options) 'use_strict_mode' => true, 'use_cookies' => true, 'use_only_cookies' => true, + 'cookie_samesite' => true, 'referer_check' => true, 'cache_limiter' => true, 'cache_expire' => true, @@ -243,14 +244,19 @@ public function start($readonly = false) if ($sessionExists) { $params = session_get_cookie_params(); + $cookie_options = array ( + 'expires' => time() + $params['lifetime'], + 'path' => $params['path'], + 'domain' => $params['domain'], + 'secure' => $params['secure'], + 'httponly' => $params['httponly'], + 'samesite' => $params['samesite'] + ); + setcookie( $sessionName, session_id(), - time() + $params['lifetime'], - $params['path'], - $params['domain'], - $params['secure'], - $params['httponly'] + $cookie_options ); } @@ -309,14 +315,20 @@ public function regenerateId() public function invalidate() { $params = session_get_cookie_params(); + + $cookie_options = array ( + 'expires' => time() - 42000, + 'path' => $params['path'], + 'domain' => $params['domain'], + 'secure' => $params['secure'], + 'httponly' => $params['httponly'], + 'samesite' => $params['samesite'] + ); + setcookie( session_name(), '', - time() - 42000, - $params['path'], - $params['domain'], - $params['secure'], - $params['httponly'] + $cookie_options ); if ($this->isSessionStarted()) {