CakePHP 2.3 sets the Session variables (including cookie attributes) in the core.php file. I need to set samesite=None
and Secure=true
for the session cookie, but it doesn't appear to have those settings available in the configuration, which shows only the following options:
Session.cookie
- The name of the cookie to use. Defaults to 'CAKEPHP'Session.timeout
- The number of minutes you want sessions to live for. This timeout is handled by CakePHPSession.cookieTimeout
- The number of minutes you want session cookies to live for.Session.checkAgent
- Do you want the user agent to be checked when starting sessions? You might want to set the value to false, when dealing with older versions of IE, Chrome Frame or certain web-browsing devices and AJAXSession.defaults
- The default configuration set to use as a basis for your session. There are four builtins: php, cake, cache, database.Session.handler
- Can be used to enable a custom session handler. Expects an array of of callables, that can be used with session_save_handler
. Using this option will automatically add session.save_handler
to the ini array.Session.autoRegenerate
- Enabling this setting, turns on automatic renewal of sessions, and
sessionids that change frequently. See CakeSession::$requestCountdown.Session.ini
- An associative array of additional ini values to set.This is how I have it now:
Configure::write('Session', array(
'defaults' => 'database',
'handler' => array('model' => 'cake_sessions'),
'timeout' => 60
));
Is there a workaround for this? I've been looking at how to do this with php but I'm not sure how I would edit the session cookie that CakePHP creates with the attributes I want, or if that is possible at all once the cookie has been created.
In PHP versions earlier than PHP 7.3, you can inject the SameSite
attribute by utilizing the cookie path hack, which consists of appending further cookie attributes to the path, by simply closing the path of with a semicolon.
Simply configure the session.cookie_path
ini option in app/Config/core.php
accordingly, for example like this in case your application's base path is /
:
Configure::write('Session', [
'defaults' => 'php',
'ini' => [
'session.cookie_path' => '/; SameSite=None',
],
]);
The Secure
attribute (ie the session.cookie_secure
ini option) will automatically be configured by CakePHP when you're visiting your site via https
.
In PHP versions as of PHP 7.3 you would use the session.cookie_samesite
ini option instead:
Configure::write('Session', [
'defaults' => 'php',
'ini' => [
'session.cookie_samesite' => 'None',
],
]);
All of this of course only applies to session cookies, if you're using additional cookies via the Cookie component, then you'd have to utilize the path hack there too, by modifying the $path
property accordingly, and unlike with sessions, you'd have to explicitly enable secure cookies:
$this->Cookie->path = '/; SameSite=None';
$this->Cookie->secure = true;
With PHP 7.3+ you'd have to use a custom/extended cookie component, and an extended/custom response class where you'd override the CookieComponent::_write()
, CakeResponse::cookie()
and CakeResponse::_setCookies()
methods accordingly, so that the component allows to set an option for same site, and the response will pass it over to the setcookie()
call.
Example:
<?php
// in app/Controller/Component/AppCookieComponent.php
App::uses('CookieComponent', 'Controller/Component');
class AppCookieComponent extends CookieComponent
{
public $sameSite = 'Lax';
protected function _write($name, $value)
{
$this->_response->cookie(array(
'name' => $this->name . $name,
'value' => $this->_encrypt($value),
'expire' => $this->_expires,
'path' => $this->path,
'domain' => $this->domain,
'secure' => $this->secure,
'httpOnly' => $this->httpOnly,
'sameSite' => $this->sameSite,
));
if (!empty($this->_reset)) {
$this->_expires = $this->_reset;
$this->_reset = null;
}
}
}
<?php
// in app/Network/AppResponse.php
App::uses('CakeResponse', 'Network');
class AppResponse extends CakeResponse
{
public function cookie($options = null)
{
$options += [
'sameSite' => 'Lax',
];
return parent::cookie($options);
}
protected function _setCookies()
{
foreach ($this->_cookies as $name => $cookie) {
$options = [
'expires' => $cookie['expire'],
'path' => $cookie['path'],
'domain' => $cookie['domain'],
'secure' => $cookie['secure'],
'httponly' => $cookie['httpOnly'],
'samesite' => $cookie['sameSite'],
];
setcookie($name, $cookie['value'], $options);
}
}
}
Inject the custom response in the front controller:
// in app/webroot/index.php
App::uses('Network', 'AppResponse');
$Dispatcher = new Dispatcher();
$Dispatcher->dispatch(
new CakeRequest(),
new AppResponse()
);
Alias the Cookie
component with the custom component class:
// in app/Controller/AppController.php
public $components = [
'Cookie' => [
'className' => 'AppCookie',
],
];
and then configure the component accordingly before using it:
$this->Cookie->sameSite = 'None';
$this->Cookie->secure = true;
or use the response object directly to set your cookies:
$this->response->cookie([
'name' => 'cookie name',
'value' => 'cookie value',
'expire' => time() + (60 * 24),
'path' => '/',
'domain' => '',
'secure' => true,
'httpOnly' => false,
'sameSite' => 'None',
]);