この記事で紹介する Laravel の話は少なくとも 5.6~9.xのバージョンで共通です。
Laravel には CSRF という攻撃の対策がデフォルトで含まれています。CSRF は正当なユーザーをどうにかこうにかして別サイト上から正当な認証情報でリクエストを送らせる攻撃です。
情報処理推進機構:情報セキュリティ:脆弱性関連情報の取扱い:知っていますか?脆弱性 (ぜいじゃくせい)/3. CSRF (クロスサイト・リクエスト・フォージェリ)
CSRF保護 9.x Laravel
CSRF保護機能は Laravel で作ったアプリケーションのサイトの中でのみ取得できるトークンを発行し、作成・更新・削除といったデータを変更するリクエスト時には必ずそのトークンを検証する、という機能です。ちなみにこの機能が働くのは厳密には HEAD、GET、OPTION以外のメソッドであるか否かです。例えば GET メソッドでデータを変更するようなアンチパターンを作るとこのCSRF保護機能は働きません。余談ですが、GET メソッドでデータを変更できるようにすると検索エンジンのクローラー、リンク切れのチェッカー、選択すべき閲覧履歴を間違えてクリックする人間などが予期せぬデータ変更を行ってしまいます。Laravel 云々抜きでも GET メソッドでデータを変更できるべきではありません。
CSRF保護機能ですが、この防御機能の適用外となる URL を設定できます。あまり使うべき設定ではありませんが、やんごとなき理由で必要になる時もあります。これはドキュメントの次リンクの部分に書かれており、
CSRF保護 9.x Laravel#CSRF保護から除外するURI
次の引用の様に設定できます。
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* CSRF検証から除外するURI
*
* @var array
*/
protected $except = [
'stripe/*',
'http://example.com/foo/bar',
'http://example.com/foo/*',
];
}
この設定値にリクエストURLが含まれるかの検証には Str::is が使われており、*がワイルドカードとして使えます。これだけでも便利なのですがプロパティに直に定義する都合上、関数や文を使えないという問題もあります。
もし関数を使おうとするとFatal error: Constant expression contains invalid operationsとエラーが出力されます。この対策としてプロパティではなくプロパティが使われる部分を改変するという方法があります。これは次の様にできます。
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* @var array<int, string>
*/
protected $except = [
];
/**
* リクエストがCSRF検証を通過すべきURIが否かを判断する.
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function inExceptArray($request)
{
// 使用直前でプロパティに色々追加
$this->except[] = config('auth.csrf.expect');
// 追加したら本来の処理に渡す
return parent::inExceptArray($request);
}
}
expect プロパティが使われいている検証用メソッドの中で expect プロパティを操作します。これで文も関数も使えます。めったに使うことはないですが、もし関数等を使う必要はある場合はおそらく一番読みやすさを保てる書き方かと思います。