CSRF保護

リクエストの作成

Laravelは、InertiaまたはAxiosを介してリクエストを行う際に、適切なCSRFトークンを自動的に含めます。ただし、Laravelを使用している場合は、プロジェクトからcsrf-tokenメタタグを省略してください。これにより、CSRFトークンが適切に更新されなくなります。

サーバーサイドフレームワークにクロスサイトリクエストフォージェリ(CSRF)保護が含まれている場合は、Inertiaのリクエストごとに、POSTPUT PATCH、およびDELETEリクエストに必要なCSRFトークンが含まれていることを確認する必要があります。

もちろん、すでに説明したように、Laravelなどの一部のサーバーサイドフレームワークは、リクエストを行う際にCSRFトークンの包含を自動的に処理します。 したがって、これらのフレームワークのいずれかを使用する場合、追加の設定は必要ありません。

ただし、CSRF保護を手動で処理する必要がある場合は、すべてのレスポンスにプロパティとしてCSRFトークンを含める方法があります。その後、Inertiaリクエストを行うときにトークンを使用できます。

import { router, usePage } from '@inertiajs/vue3'

const page = usePage()

router.post('/users', {
  _token: page.props.csrf_token,
  name: 'John Doe',
  email: 'john.doe@example.com',
})

Inertiaの共有データ機能を使用して、csrf_tokenを各レスポンスに自動的に含めることもできます。 csrf_tokenを各レスポンスに自動的に含めることもできます。

ただし、より良い方法は、axiosに組み込まれているCSRF機能を使用することです。Axiosは、Inertiaが内部で使用するHTTPライブラリです。 axios for this. Axios is the HTTP library that Inertia uses under the hood.

Axiosは、XSRF-TOKEN Cookieの存在を自動的にチェックします。存在する場合、Axiosは、作成するリクエストに対して、X-XSRF-TOKENヘッダーにトークンを含めます。

これを実装する最も簡単な方法は、サーバーサイドミドルウェアを使用することです。各レスポンスにXSRF-TOKEN Cookieを含め、axiosからのリクエストで送信されたX-XSRF-TOKENヘッダーを使用してトークンを検証します。cookie on each response, and then verify the token using the X-XSRF-TOKEN header sent in the requests from axios.

不一致の処理

CSRFトークンの不一致が発生すると、サーバーサイドフレームワークはおそらくエラーレスポンスを引き起こす例外をスローします。たとえば、Laravelを使用すると、TokenMismatchExceptionがスローされ、419エラーページになります。これは有効なInertiaレスポンスではないため、エラーがモーダルで表示されます。

明らかに、これは優れたユーザーエクスペリエンスではありません。これらのエラーを処理するより良い方法は、前のページへのリダイレクトを返し、ページが期限切れになったというフラッシュメッセージを表示することです。これにより、フラッシュメッセージがプロパティとして利用可能な有効なInertiaレスポンスが生成され、ユーザーに表示できます。もちろん、これが機能するためには、フラッシュメッセージをInertiaと共有する必要があります。

Laravelを使用する場合、アプリケーションの例外ハンドラーを変更して、ユーザーを以前のページに自動的にリダイレクトさせ、メッセージをセッションにフラッシュできます。これを実現するには、アプリケーションのbootstrap/app.phpファイルで、respond例外メソッドを使用できます。

use Symfony\Component\HttpFoundation\Response;

->withExceptions(function (Exceptions $exceptions) {
    $exceptions->respond(function (Response $response) {
        if ($response->getStatusCode() === 419) {
            return back()->with([
                'message' => 'The page expired, please try again.',
            ]);
        }

        return $response;
    });
});

最終的には、ユーザーにとって非常に優れたエクスペリエンスになります。エラーモーダルが表示される代わりに、ページが「期限切れ」になったというメッセージが表示され、もう一度やり直すように求められます。