[CakePHP4] CSRFプロテクション

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で追加したのかな。

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>