CakePHP 4 で CSRF 保護を一部または完全に無効化(有効化)する方法

はじめに
CakePHP 4 ではデフォルトで CSRF 保護が有効になっています。しかし API の実装など CSRF 保護を使わない場合もあります。
今日は CakePHP 4 で CSRF 保護を一部もしくは全体で無効化(有効化)する方法をご紹介します。
今回使用したのは CakePHP 4.0.8 です
1. 下準備
今回は Samples コントローラに add と edit の2つのアクションをつくり、テンプレートは共用にしました。テンプレートには CSRF トークンを含めず、CSRF 保護が有効な場合には送信時にエラーが出るようにしています。
<?php
declare(strict_types=1);
namespace App\Controller;
class SamplesController extends AppController
{
public function add()
{
return $this->render('form');
}
public function edit()
{
return $this->render('form');
}
}
<h1><?= $this->request->getParam('action') ?></h1>
<form method="post">
<button type="submit">submit</button>
</form>
2. 完全に無効
CSRF 保護を全アクションで無効化する方法は src/Application.php の当該箇所をコメントアウト(もしくは削除)するだけです。
// ▼ ここをコメントアウト or 削除
// Cross Site Request Forgery (CSRF) Protection Middleware
// https://book.cakephp.org/4/en/controllers/middleware.html#cross-site-request-forgery-csrf-middleware
// ->add(new CsrfProtectionMiddleware([
// 'httponly' => true,
// ]));
;
3. 一部のアクションで無効 or 有効
一部分だけを無効化するには skipCheckCallback() を使って実装できます。
下記コードでは Samples コントローラの edit アクションのみ無効化しています。
(add 画面では有効なので、送信すると InvalidCsrfTokenException のエラーが出ます)
IF 文の条件式を変えれば「特定のアクションだけ有効」(= 特定のアクション以外は無効)にすることもできますね。
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
$middlewareQueue
...
// ▼ ここをコメントアウト or 削除
// Cross Site Request Forgery (CSRF) Protection Middleware
// https://book.cakephp.org/4/en/controllers/middleware.html#cross-site-request-forgery-csrf-middleware
// ->add(new CsrfProtectionMiddleware([
// 'httponly' => true,
// ]));
;
// ▼下記を追加
$csrf = new CsrfProtectionMiddleware([
'httponly' => true,
]);
$csrf->skipCheckCallback(function ($request) {
if (
$request->getParam('controller') === 'Samples'
&& $request->getParam('action') === 'edit'
) {
return true;
}
});
$middlewareQueue->add($csrf);
return $middlewareQueue;
}
公式ドキュメントでは Prefix Routing を用いている場合のサンプルコードが紹介されています。
サンプルコードは下記「Cross Site Request Forgery (CSRF) Middleware」ページのやや下部にあります
- Cross Site Request Forgery (CSRF) Middleware (CakePHP 4.x Cookbook)
- https://book.cakephp.org/4/en/controllers/middleware.html#cross-site-request-forgery-csrf-middleware
- Prefix Routing (CakePHP 4.x Cookbook)
- https://book.cakephp.org/4/en/development/routing.html#prefix-routing
- Connecting Routes (CakePHP 4.x Cookbook)
- https://book.cakephp.org/4/en/development/routing.html#routes-configuration
4. 特定スコープのみ有効
ルーティング設定で、特定スコープの場合だけ CSRF を有効化することができます。
例えば、下記のように設定すれば /my-samples でアクセスしたときだけ CSRF 保護が有効になります。
// ▼ ここをコメントアウト or 削除
// Cross Site Request Forgery (CSRF) Protection Middleware
// https://book.cakephp.org/4/en/controllers/middleware.html#cross-site-request-forgery-csrf-middleware
// ->add(new CsrfProtectionMiddleware([
// 'httponly' => true,
// ]));
;
<?php
...
use Cake\Http\Middleware\CsrfProtectionMiddleware; // ←追加
use Cake\Routing\Route\DashedRoute;
use Cake\Routing\RouteBuilder;
...
// ▼これを追加
$routes->scope('/my-samples', function (RouteBUilder $builder) {
// CSRF 保護を有効化
$builder->registerMiddleware('csrf', new CsrfProtectionMiddleware([
'httpOnly' => true,
]));
$builder->applyMiddleware('csrf');
// /my-samples で /samples/edit にアクセス
$builder->connect('/', ['controller' => 'Samples', 'action' => 'edit']);
});
...
この route.php で設定する方法は、公式ドキュメントの「Cross Site Request Forgery (CSRF) Middleware」に Application.php に書くサンプルがあるのですが、うまく動かすことができず、同じくチュートリアルにある「Finding Articles By Tags」を参考にしました。
- Cross Site Request Forgery (CSRF) Middleware (CakePHP 4.x Cookbook)
- https://book.cakephp.org/4/en/controllers/middleware.html#cross-site-request-forgery-csrf-middleware
- Finding Articles By Tags (CakePHP 4.x Cookbook)
- https://book.cakephp.org/4/en/tutorials-and-examples/cms/tags-and-users.html#finding-articles-by-tags
5. おわりに
CakePHP では CSRF 保護を柔軟に設定することができます。
これらの機能を使わなくても実装できるかもしれませんが、うまく使うことで開発効率と保守性が高まりますので、用途に応じて使い分けるのがオススメです。