🔧

セッション切断時にPOST通信をし419エラーになるのを防ぐ方法

2021/12/30に公開

はじめに

セキュリティ上の理由からセッションの持続時間を設定することはよくあると思いますが、セッションが切れた時の対応は見落としがちです。
今回はLaravelでセッションが切れた状態でPOST通信を行った際に419エラーになるのを防ぐ方法を見ていきたいと思います。

419エラーにならないための対処法

セッションの有効期限が切れた状態でPOST通信を行うと、CSRFトークンの有効期限切れのため419エラーが表示されるようになっています。
しかし、ユーザーは419エラーの画面を見ても原因がわからず親切とは言えません。

今回作成していたサービスではセッションの有効期限が切れてGET通信を行った際にはログイン画面へリダイレクトするようにしていたため、POST通信の場合も同様の挙動となるようにしたいと思います。

Laravelにおけるエラー発生時の挙動について、公式ドキュメントには下記のように書かれています。

エラーと例外の処理は、新しいLaravelプロジェクトの開始時に最初から設定されています。App\Exceptions\Handlerクラスは、アプリケーションが投げるすべての例外がログに記録され、ユーザーへレンダーする場所です。

Laravel 8.x エラー処理

そこでApp\Exceptions\Handlerを見てみると、render()メソッド内の$e = $this->prepareException($e);に下記のように書かれていました。

    /**
     * Prepare exception for rendering.
     *
     * @param  \Throwable  $e
     * @return \Throwable
     */
    protected function prepareException(Throwable $e)
    {
        if ($e instanceof ModelNotFoundException) {
            $e = new NotFoundHttpException($e->getMessage(), $e);
        } elseif ($e instanceof AuthorizationException) {
            $e = new AccessDeniedHttpException($e->getMessage(), $e);
        } elseif ($e instanceof TokenMismatchException) { // ここでCSFトークンが有効期限切れの場合は419エラーを返すようにしている
            $e = new HttpException(419, $e->getMessage(), $e);
        } elseif ($e instanceof SuspiciousOperationException) {
            $e = new NotFoundHttpException('Bad hostname provided.', $e);
        }

        return $e;
    }

CSRFの有効期限切れの場合は、prepareException()へ飛ばさずにリダイレクトするようにしてあげれば良さそうです。
そこで、render()メソッドをオーバーライドするために、app/Exceptions/Handler.phpに下記のコードを追加しました。

 public function render($request, \Throwable $e)
    {
        if ($e instanceof TokenMismatchException) {
            return redirect()
                    ->back();
        }
        return parent::render($request, $e);
    }

これでセッションの有効期限が切れた状態でPOST通信を行った場合でも、419エラーにならずログイン画面へリダイレクトすることができるようになりました!

最後に

POST通信を行う直前で長時間放置するようなケースは稀かと思われるため、今回のようなエラーが発見されるケースは稀なのではないかと感じました。
新しいプロジェクトに携わる際には、ここら辺もきちんと設定をしてリリースできるようにしていきたいです。

最後まで読んでいただきありがとうございました!

参考

https://gist.github.com/jrmadsen67/bd0f9ad0ef1ed6bb594e
https://qiita.com/kd9951/items/b1bccc4666976ec90dcc

Discussion