メインコンテンツまでスキップ

CSRF保護

導入

クロスサイトリクエストフォージェリ(CSRF)は、認証されたユーザーの代わりに不正なコマンドが実行される悪意のあるエクスプロイトの一種です。幸いにも、Laravelを使用すれば、クロスサイトリクエストフォージェリ(CSRF)攻撃からアプリケーションを簡単に保護することができます。

脆弱性の説明

クロスサイトリクエストフォージェリについてよく知らない場合は、この脆弱性がどのように悪用されるかについて説明しましょう。アプリケーションには /user/email ルートがあり、認証されたユーザーのメールアドレスを変更するための POST リクエストを受け入れるとします。おそらく、このルートは、ユーザーが使用したいメールアドレスを含む email 入力フィールドを期待しているでしょう。

CSRF保護がない場合、悪意のあるウェブサイトは、自分自身のメールアドレスを提出するHTMLフォームを作成し、アプリケーションの /user/email ルートを指すことができます:

<form action="https://your-application.com/user/email" method="POST">
<input type="email" value="malicious-email@example.com">
</form>

<script>
document.forms[0].submit();
</script>

悪意のあるウェブサイトがページが読み込まれると自動的にフォームを送信する場合、悪意のあるユーザーは、あなたのアプリケーションの無防備なユーザーを自分のウェブサイトに誘導するだけで、そのユーザーのメールアドレスがあなたのアプリケーションで変更されます。

この脆弱性を防ぐためには、悪意のあるアプリケーションがアクセスできない秘密のセッション値を、すべての受信 POSTPUTPATCH、または DELETE リクエストに対して検査する必要があります。

CSRFリクエストの防止

Laravelは、アプリケーションによって管理される各アクティブなユーザーセッションに対してCSRF「トークン」を自動的に生成します。このトークンは、認証されたユーザーが実際にアプリケーションにリクエストを行っていることを検証するために使用されます。このトークンはユーザーのセッションに保存され、セッションが再生成されるたびに変更されるため、悪意のあるアプリケーションはアクセスできません。

現在のセッションのCSRFトークンは、リクエストのセッションまたはcsrf_tokenヘルパー関数を介してアクセスできます:

    use Illuminate\Http\Request;

Route::get('/token', function (Request $request) {
$token = $request->session()->token();

$token = csrf_token();

// ...
});

アプリケーション内で "POST"、"PUT"、"PATCH"、または "DELETE" HTMLフォームを定義する場合は、CSRF保護ミドルウェアがリクエストを検証できるように、フォームに隠しCSRF _tokenフィールドを含める必要があります。便宜上、@csrf Bladeディレクティブを使用して隠しトークン入力フィールドを生成できます:

<form method="POST" action="/profile">
@csrf

<!-- Equivalent to... -->
<input type="hidden" name="_token" value="{{ csrf_token() }}" />
</form>

デフォルトでwebミドルウェアグループに含まれるIlluminate\Foundation\Http\Middleware\ValidateCsrfToken ミドルウェアは、リクエスト入力のトークンがセッションに格納されているトークンと一致するかどうかを自動的に検証します。これらの2つのトークンが一致すると、認証されたユーザーがリクエストを開始していることがわかります。

CSRFトークンとSPA

LaravelをAPIバックエンドとして利用するSPAを構築している場合は、APIとの認証およびCSRF脆弱性に対する保護に関する情報については、Laravel Sanctumドキュメントを参照してください。

CSRF保護からURIを除外する

時には、一連のURIをCSRF保護から除外したい場合があります。たとえば、Stripeを使用して支払いを処理し、そのWebhookシステムを利用している場合は、Stripeがルートに送信するCSRFトークンを知らないため、StripeのWebhookハンドラルートをCSRF保護から除外する必要があります。

通常、これらの種類のルートは、Laravelがroutes/web.phpファイルのすべてのルートに適用するwebミドルウェアグループの外に配置する必要があります。ただし、アプリケーションのbootstrap/app.phpファイルでvalidateCsrfTokensメソッドにそれらのURIを提供することで、特定のルートを除外することもできます:

    ->withMiddleware(function (Middleware $middleware) {
$middleware->validateCsrfTokens(except: [
'stripe/*',
'http://example.com/foo/bar',
'http://example.com/foo/*',
]);
})

注記

テストを実行する際には、便宜上、すべてのルートでCSRFミドルウェアが自動的に無効になります。

X-CSRF-TOKEN

CSRF トークンを POST パラメータとしてチェックするだけでなく、web ミドルウェアグループにデフォルトで含まれる Illuminate\Foundation\Http\Middleware\ValidateCsrfToken ミドルウェアは、X-CSRF-TOKEN リクエストヘッダもチェックします。たとえば、HTML の meta タグにトークンを保存することができます:

<meta name="csrf-token" content="{{ csrf_token() }}">

その後、jQuery のようなライブラリに、すべてのリクエストヘッダにトークンを自動的に追加するよう指示できます。これにより、従来の JavaScript テクノロジを使用した AJAX ベースのアプリケーションに対して簡単で便利な CSRF 保護が提供されます:

$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});

X-XSRF-TOKEN

Laravel は、フレームワークによって生成される各レスポンスに含まれる暗号化された XSRF-TOKEN クッキーに現在の CSRF トークンを保存します。このクッキーの値を使用して X-XSRF-TOKEN リクエストヘッダを設定できます。

このクッキーは、いくつかの JavaScript フレームワークやライブラリ(Angular や Axios のような)が、同一オリジンのリクエストで X-XSRF-TOKEN ヘッダにその値を自動的に配置するため、主に開発者の利便性のために送信されます。

注記

デフォルトでは、resources/js/bootstrap.js ファイルには、X-XSRF-TOKEN ヘッダを自動的に送信する Axios HTTP ライブラリが含まれています。