CakePHP4ではCSRFの対策として、
CsrfProtectionMiddleware
と
SessionCsrfProtectionMiddleware
の2種類がある。
CsrfProtectionMiddleware
CakePHP3.5で追加されCakePHP4でも使われているプロテクション。
アクセス時に、CookieにCSRFトークンを持たせ、POST時にそのトークンを使うことで、同一ブラウザからのアクセスであることを保証するらしい。
仕組みはよくわからないが、サーバーにstateが無くても、CSRFチェックができるらしい。
なので、入力画面でうなってるうちにセッションが切れても、CSRFチェックはできるので、便利といえば便利な模様。
SessionCsrfProtectionMiddleware
CakePHP4.2で追加されたプロテクション。
従来の CsrfProtectionMiddlewareは、CookieにあるCSRFトークンだけで完結していたが、こっちはよくあるセッションに値を持たせているタイプ。セッションが有効なうちだけ使えるので、より短期間で厳密な場合にいいかもしれない。
ちなみに同時に使うことはできない。
使い方
どっちも、Application.phpで設定できる。
// src/Application.php
// クッキーベースの CSRF トークンの場合
use Cake\Http\Middleware\CsrfProtectionMiddleware;
// セッションベースの CSRF トークンの場合
use Cake\Http\Middleware\SessionCsrfProtectionMiddleware;
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
$options = [
// ...
];
$csrf = new CsrfProtectionMiddleware($options);
// または
$csrf = new SessionCsrfProtectionMiddleware($options);
$middlewareQueue->add($csrf);
return $middlewareQueue;
}
特定の範囲だけCSRFをかけることもできる模様。SessionCsrfのほうはできるか不明
// src/Application.php
use Cake\Http\Middleware\CsrfProtectionMiddleware;
public function routes(RouteBuilder $routes) : void
{
$options = [
// ...
];
$routes->registerMiddleware('csrf', new CsrfProtectionMiddleware($options));
parent::routes($routes);
}
// config/routes.php
$routes->scope('/', function (RouteBuilder $routes) {
$routes->applyMiddleware('csrf');
});
あとは、Formヘルパーでcreateを呼べば、勝手にhidden属性のinputが含まれる
<input type="hidden" name="_csrfToken" autocomplete="off" value="b9eb6・・・・・edee555"/>
Formヘルパーを使わない場合は手動で設定する必要がある。
requestからとれるので、どっかに入れ込めば動く。
$token = $this->request->getAttribute('csrfToken');
Ajaxで使う場合
javascriptからPOSTする場合などでトークンを必要とする場合も、
echo $this->Html->meta('csrfToken', $this->request->getAttribute('csrfToken'));
って感じで、HTML内に突っ込んで、jQueryとかで以下のように取ってきて、X-CSRF-Token ヘッダーを介して送信できるので、めっちゃ簡単。
var csrf = $('meta[name="csrfToken"]').attr('content');
$.ajax({
method: "POST",
url: "/Like/add",
headers:{'X-CSRF-Token': csrf},
data: {'data' : 'mogemoge'}
}).done(function(){
//
}).error(function(){
//
});
そのほかの機能
特定のアクションはチェックをスキップしたり、Cookieのexpireやsamesiteとかを変えれたりする模様。
まぁ、その辺りは、ドキュメントを参考にしたほうがいい。
まとめ
Sessionベースのほうは使ってないので、まだよく分からないが、CakePHP2の頃に比べると、こんなんで大丈夫なのかなっていうくらい簡単に使える。
サーバーにstateが無くても、CSRFチェックができる仕組みが、よく分からないので、もう少しそこをドキュメントで記述してほしいな・・・。
コードを追いかけるのめんどいし。
不安っていう人がSessionベースを4.2で追加したのかな。