0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Laravel】フォーム送信時に419 Page Expiredが発生する件について調べてみた

Last updated at Posted at 2022-01-08

#概要
本記事は、PHPフレームワークLaravel入門 第2版で学習している中の疑問・つまづきの備忘録です。

今回はCSRF対策の際のエラー解決と根本原因についてまとめます。

#発生したエラー

フォーム送信時に以下のエラーが発生しました。

スクリーンショット 2022-01-08 12.03.56.png

##ソースコード

index.blade.php
<form action="/hello" method="post">
    <table>

        ///////中略

        <tr>
            <th>Message: </th>
            <td>
                <input type="text" name="msg" value="{{ old('msg') }}">
            </td>
        </tr>
    </table>
</form>

VerifyCsrfToken.php
<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
    protected $except = [
        // 
    ];
}

##原因
以下の2点が原因です。

  • index.blade.phpのformタグ内に@csrfディレクティブを記載していない

  • にも関わらず、VerifyCsrfTokenクラスの配列$exceptにCSRF対策から除外するアクション名を記載していない

##解決策1(CSRF対策を行いたい場合)

index.blade.phpのformタグ内に@csrfディレクティブを追記

index.blade.php
<form action="/hello" method="post">
    <table>
        @csrf //これを追記する

        ///////中略

        <tr>
            <th>Message: </th>
            <td>
                <input type="text" name="msg" value="{{ old('msg') }}">
            </td>
        </tr>
    </table>
</form>

##解決策2(CSRF対策を行わない・必要ない場合)

VerifyCsrfTokenクラスの配列$exceptにCSRF対策から除外するアクション名を追記

※この場合formタグに@csrfディレクティブの追記は不要

VerifyCsrfToken.php
<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
    protected $except = [
        'hello', //helloアクションではCSRF対策を行わない指定
    ];
}

##なぜ上記の対応を行わないと419 Page Expiredが発生するのか

こうすればエラーが解消できる!というのは分かりましたが、なぜこのような対応が必要なのでしょうか。
裏側で何が起こっているのか調べてみました。

答えはLaravel 8.x CSRF保護に記載がありました。

アプリケーションで"POST"、"PUT"、"PATCH"、"DELETE" HTMLフォームを定義するときはいつでも、CSRF保護ミドルウェアがリクエストを検証できるように、フォームに非表示のCSRF_tokenフィールドを含める必要があります。便利なように、@csrf Bladeディレクティブを使用して、非表示のトークン入力フィールドを生成できます。

Laravelを使用しないPHPでの開発の際に必要だったtype="hidden"でvalueにトークンを持つinputタグを自動で生成してくれています。

<form method="POST" action="/profile">
    @csrf
    <!-- Equivalent to... -->
    <input type="hidden" name="_token" value="{{ csrf_token() }}" /> //生成されるタグのトークン入力フィールド
</form>

さらに、

webミドルウェアグループへデフォルトで含まれているApp\Http\Middleware\VerificationCsrfTokenミドルウェアは、リクエスト入力のトークンがセッションに保存されたトークンと一致するかを自動的に検証します。この2トークンが一致すれば、認証済みユーザーがリクエストを開始したことがわかります。

つまり今回は

  • index.blade.phpのフォームに@csrfディレクティブが記載されておらず、トークンを持つinputタグが生成されていなかった
  • VerificationCsrfTokenクラスの配列$exceptでCSRF対策を除外したい当該のフォーム送信時のアクション名が追加されていなかった
  • VerificationCsrfTokenで入力トークン検証が失敗した

という理由でフォーム送信時に419 Page Expiredが発生したようです。

#まとめ
CSRF対策する場合は、formタグに@csrfディレクティブを記載する。
しない場合はVerificationCsrfTokenクラスの配列$exceptにCSRF対策から除外するアクション名を追記する。

色々と調べてみると新たな発見があって楽しいですね!

#参考文献

PHPフレームワークLaravel入門 第2版
Laravel 8.x CSRF保護

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?