はじめに
Laravelの学習中、formタグを使用する際には以下のように@csrfの記述が必須であることがわかりました。
<form method="POST" action="/profile">
@csrf
...
</form>
この場合@csrfを書かないでPOSTした場合は419エラーになリます。
CSRFとはなにか?なぜ記述する必要があるのか初学者視点で解説したいと思います。
この記事の対象者としては
- CSRFが何か、なぜ対策が必要なのかわからない方
- Laravel初心者の方
を想定しております。
CSRF(クロスサイトリクエストフォージェリ)とは
CSRFは、攻撃者がユーザーの意図しないリクエストを行わせることによって、Webサイト上での操作を不正に行う攻撃手法です。攻撃者は、被害者が認証済みの状態で悪意のあるWebページにアクセスすることを誘導します。
攻撃手法
①攻撃者は攻撃用Webページを準備し、ユーザがアクセスするよう誘導する。
②被害者が攻撃用のWebページを開くと、そのページ内には攻撃者が用意した不正なリクエストが含まれている。
③ブラウザは被害者のクッキーを自動的に付与し、不正なリクエストが攻撃対象のWebサイトに送信される。
④攻撃対象のWebサイトは、ユーザーが意図しない操作を実行してしまう。
被害の例
ユーザーがオンラインバンキングシステムAにログインしているとします。このユーザーは、定期的に送金を行うためのフォームを使用します。しかし、攻撃者がユーザーが訪れる可能性のある悪意のあるWebページを作成し、その中には攻撃者が用意した不正な送金リクエストが含まれているとします。
ユーザーが攻撃者のWebページにアクセスすると、そのWebページ内のリクエストがオンラインバンキングシステムAに自動的に送信され、ユーザーが意図しない形で資金が移動してしまいます。ユーザーがログイン済みであるため、システムはリクエストを正当なものと認識し、不正な送金が実行されてしまいます。
CSRF攻撃の対策をしていないと、攻撃者は不正に取得したセッションIDを使用して、ユーザのアカウントで操作を行ったり、データを変更したりすることが可能になります。
なぜ@csrfと記述するだけで攻撃を防げるのか?
Laravelでは、"POST"、"PUT"、"PATCH"、"DELETE"のHTMLフォームを定義するときはいつでも、CSRF保護ミドルウェアがリクエストを検証できるように、フォームに非表示のCSRF_tokenフィールドを含める必要があります。
Laravelではビューでformの内部に@csrfと記述するだけで自動的にCSRFトークンを生成し、フォームの隠しフィールドに埋め込むことができます。
<form method="POST" action="/hoge">
@csrf
<input name="hoge" value="{{ $hoge }}">
<button type="submit">送信</button>
</form>
トークンはリクエストが処理される前に生成され、その後、フォームなどの入力フィールドに埋め込まれます。これにより、送信されるリクエストに正しいトークンが含まれ、セッションに入っているトークンの値と一致しているかサーバーで検証されることになります。
このCSRFトークンはセッションが再生成されるたびに変更されるため、悪意のあるアプリケーションはこのトークンへアクセスできません。
また、現在のセッションのCSRFトークンには、リクエストのセッションまたはcsrf_tokenヘルパ関数を介してアクセスできます。
use Illuminate\Http\Request;
Route::get('/token', function (Request $request) {
$token = $request->session()->token();
$token = csrf_token();
// ...
});
まとめ
この記事では、LaravelにおけるCSRF攻撃とその対策方法について解説しました。CSRF攻撃はユーザーの意図しないリクエストを利用して不正な操作を行う手法であり、formの中に@csrfを記述することによって、Laravelは自動的にCSRFトークンを生成し、悪意のあるリクエストを防ぎます。