如何在 CakePHP 3.4 上将 CSRF cookie 设置为 samesite?
How to set CSRF cookie to samesite on CakePHP 3.4?
我正在使用 CakePHP 3.4(无法升级)并且为了保护系统免受 跨站请求伪造 我需要将 CSRF 令牌 cookie 设置为 SameSite =严格的。但是,这个版本的CakePHP似乎无法处理这样的设置。
我尝试使用 CsrfComponent class 并在 AppController 中加载该组件
$this->loadComponent('Csrf', [
'secure' => true,
'httpOnly' => true,
]);
如何将此 cookie 设置为 SameSite = Strict 或其他替代方法以防止跨站点请求伪造?
在 CakePHP 3.9.3 中添加了对带有 CSRF cookie 的 samesite 的支持,不过您必须切换到 CSRF 保护中间件。
如果您无法升级,那么您将使用一些自定义代码,即接受属性的更多选项的 custom/extended CSRF 组件,以及创建的 custom/exteneded 响应对象相应地具有该属性的 cookie。
在PHP 7.3之前的PHP版本中,您可以分别必须利用cookie路径hack注入SameSite
属性,它包括通过简单地用分号关闭路径来将更多 cookie 属性附加到路径。在从 PHP 7.3 开始的 PHP 版本中,您将使用当时支持的 samesite
for setcookie()
.
顺便说一句,对于会话 cookie,您需要相应地修改 session.cookie_path
或 session.cookie_samesite
PHP INI 选项,而 CakePHP 中设置 cookie 的其他地方可能也需要进行调整,例如 cookie component,即使您的应用不使用它,它也可能被第 3 方插件使用。
示例:
<?php
// in src/Controller/Component/CsrfComponent.php
namespace App\Controller\Component;
use Cake\Controller\ComponentRegistry;
use Cake\Http\Response;
use Cake\Http\ServerRequest;
class CsrfComponent extends \Cake\Controller\Component\CsrfComponent
{
public function __construct(ComponentRegistry $registry, array $config = [])
{
// Use Lax by default
$config += [
'samsite' => 'Lax',
];
parent::__construct($registry, $config);
}
protected function _setCookie(ServerRequest $request, Response $response)
{
parent::_setCookie($request, $response);
// Add samesite option to the cookie that has been created by the parent
$cookie = $response->cookie($this->getConfig('cookieName'));
$cookie['samesite'] = $this->getConfig('samesite');
$response->cookie($cookie);
}
}
https://github.com/cakephp/cakephp/blob/3.4.14/src/Controller/Component/CsrfComponent.php#L125
// in src/Http/Response.php
namespace App\Http;
class Response extends \Cake\Http\Response
{
protected function _setCookies()
{
foreach ($this->_cookies as $name => $c) {
if (version_compare(PHP_VERSION, '7.3.0', '<')) {
// Use regular syntax (with possible path hack) in case
// no samesite has been set, or the PHP version doesn't
// support the samesite option.
if (isset($c['samesite'])) {
$c['path'] .= '; SameSite=' . $c['samesite'];
}
setcookie(
$name,
$c['value'],
$c['expire'],
$c['path'],
$c['domain'],
$c['secure'],
$c['httpOnly']
);
} else {
setcookie($name, $c['value'], [
'expires' => $c['expire'],
'path' => $c['path'],
'domain' => $c['domain'],
'secure' => $c['secure'],
'httponly' => $c['httpOnly'],
'samesite' => $c['samesite'],
]);
}
}
}
}
https://github.com/cakephp/cakephp/blob/3.4.14/src/Http/Response.php#L540
在您的 AppController
的构造函数中注入自定义响应对象:
// in src/Controller/AppController.php
use Cake\Http\Response;
use Cake\Http\ServerRequest;
// ...
class AppController extends Controller
{
// ...
public function __construct(
ServerRequest $request = null,
Response $response = null,
$name = null,
$eventManager = null,
$components = null
) {
if ($response !== null) {
throw new \InvalidArgumentException(
'This should not happen, we want to use a custom response class.'
);
}
$response = new \App\Http\Response();
parent::__construct($request, $response, $name, $eventManager, $components);
}
// ...
}
最后 alias the Csrf
component 使用自定义组件 class 并设置您的 samesite
配置:
// in src/Controller/AppController.php
// ...
class AppController extends Controller
{
// ...
public function initialize()
{
parent::initialize();
// ...
$this->loadComponent('Csrf', [
'className' => \App\Controller\Component\CsrfComponent::class,
'secure' => true,
'httpOnly' => true,
'samesite' => 'Strict',
]);
}
// ...
}
最后要注意的是,在后来的 CakePHP 3.x 版本中,cookie 数组已被 cookie 对象替换,因此需要进行相应的更改,但既然你可以'不升级,这个应该没问题,一旦决定升级,就全力以赴,升级到最新版本吧。
我正在使用 CakePHP 3.4(无法升级)并且为了保护系统免受 跨站请求伪造 我需要将 CSRF 令牌 cookie 设置为 SameSite =严格的。但是,这个版本的CakePHP似乎无法处理这样的设置。
我尝试使用 CsrfComponent class 并在 AppController 中加载该组件
$this->loadComponent('Csrf', [
'secure' => true,
'httpOnly' => true,
]);
如何将此 cookie 设置为 SameSite = Strict 或其他替代方法以防止跨站点请求伪造?
在 CakePHP 3.9.3 中添加了对带有 CSRF cookie 的 samesite 的支持,不过您必须切换到 CSRF 保护中间件。
如果您无法升级,那么您将使用一些自定义代码,即接受属性的更多选项的 custom/extended CSRF 组件,以及创建的 custom/exteneded 响应对象相应地具有该属性的 cookie。
在PHP 7.3之前的PHP版本中,您可以分别必须利用cookie路径hack注入SameSite
属性,它包括通过简单地用分号关闭路径来将更多 cookie 属性附加到路径。在从 PHP 7.3 开始的 PHP 版本中,您将使用当时支持的 samesite
for setcookie()
.
顺便说一句,对于会话 cookie,您需要相应地修改 session.cookie_path
或 session.cookie_samesite
PHP INI 选项,而 CakePHP 中设置 cookie 的其他地方可能也需要进行调整,例如 cookie component,即使您的应用不使用它,它也可能被第 3 方插件使用。
示例:
<?php
// in src/Controller/Component/CsrfComponent.php
namespace App\Controller\Component;
use Cake\Controller\ComponentRegistry;
use Cake\Http\Response;
use Cake\Http\ServerRequest;
class CsrfComponent extends \Cake\Controller\Component\CsrfComponent
{
public function __construct(ComponentRegistry $registry, array $config = [])
{
// Use Lax by default
$config += [
'samsite' => 'Lax',
];
parent::__construct($registry, $config);
}
protected function _setCookie(ServerRequest $request, Response $response)
{
parent::_setCookie($request, $response);
// Add samesite option to the cookie that has been created by the parent
$cookie = $response->cookie($this->getConfig('cookieName'));
$cookie['samesite'] = $this->getConfig('samesite');
$response->cookie($cookie);
}
}
https://github.com/cakephp/cakephp/blob/3.4.14/src/Controller/Component/CsrfComponent.php#L125
// in src/Http/Response.php
namespace App\Http;
class Response extends \Cake\Http\Response
{
protected function _setCookies()
{
foreach ($this->_cookies as $name => $c) {
if (version_compare(PHP_VERSION, '7.3.0', '<')) {
// Use regular syntax (with possible path hack) in case
// no samesite has been set, or the PHP version doesn't
// support the samesite option.
if (isset($c['samesite'])) {
$c['path'] .= '; SameSite=' . $c['samesite'];
}
setcookie(
$name,
$c['value'],
$c['expire'],
$c['path'],
$c['domain'],
$c['secure'],
$c['httpOnly']
);
} else {
setcookie($name, $c['value'], [
'expires' => $c['expire'],
'path' => $c['path'],
'domain' => $c['domain'],
'secure' => $c['secure'],
'httponly' => $c['httpOnly'],
'samesite' => $c['samesite'],
]);
}
}
}
}
https://github.com/cakephp/cakephp/blob/3.4.14/src/Http/Response.php#L540
在您的 AppController
的构造函数中注入自定义响应对象:
// in src/Controller/AppController.php
use Cake\Http\Response;
use Cake\Http\ServerRequest;
// ...
class AppController extends Controller
{
// ...
public function __construct(
ServerRequest $request = null,
Response $response = null,
$name = null,
$eventManager = null,
$components = null
) {
if ($response !== null) {
throw new \InvalidArgumentException(
'This should not happen, we want to use a custom response class.'
);
}
$response = new \App\Http\Response();
parent::__construct($request, $response, $name, $eventManager, $components);
}
// ...
}
最后 alias the Csrf
component 使用自定义组件 class 并设置您的 samesite
配置:
// in src/Controller/AppController.php
// ...
class AppController extends Controller
{
// ...
public function initialize()
{
parent::initialize();
// ...
$this->loadComponent('Csrf', [
'className' => \App\Controller\Component\CsrfComponent::class,
'secure' => true,
'httpOnly' => true,
'samesite' => 'Strict',
]);
}
// ...
}
最后要注意的是,在后来的 CakePHP 3.x 版本中,cookie 数组已被 cookie 对象替换,因此需要进行相应的更改,但既然你可以'不升级,这个应该没问题,一旦决定升级,就全力以赴,升级到最新版本吧。