👀
Laravel + Inertia.jsアプリケーションにおいて、ログアウト後のブラウザバックによる保護されたページへのアクセスを防止する方
ログアウト後のブラウザバック防止ガイド
このガイドでは、Laravel + Inertia.jsアプリケーションにおいて、ログアウト後のブラウザバックによる保護されたページへのアクセスを防止する方法について説明します。
目次
問題の概要
SPAアプリケーションにおいて、以下のようなセキュリティ上の問題が発生することがあります:
- ユーザーが保護されたページ(例:ダッシュボード)にアクセス
- ログアウトを実行
- ブラウザの戻るボタンをクリック
- キャッシュされた保護ページが表示されてしまう
この問題は、ブラウザのキャッシュ機能と認証状態の管理の間にギャップがあることに起因します。
ブラウザキャッシュの仕組み
キャッシュの基本動作
ブラウザは以下の目的でページをキャッシュします:
- 高速なページ表示
- サーバー負荷の軽減
- ネットワークトラフィックの削減
解決方法
1. キャッシュコントロール方式
主要なキャッシュコントロールヘッダー
| ヘッダー | 説明 | 効果 |
|---|---|---|
Cache-Control: no-store |
キャッシュを一切保存しない | 最も厳格な設定 |
Cache-Control: no-cache |
キャッシュ使用前に必ず再検証 | 柔軟な設定 |
Cache-Control: must-revalidate |
キャッシュの有効性を確認 | 追加的な保証 |
2. ミドルウェア認証チェック方式
3. クライアントサイド認証チェック
実装方法
1. キャッシュコントロールの実装
// app/Http/Middleware/HandleInertiaRequests.php
public function handle(Request $request, Closure $next)
{
$response = parent::handle($request, $next);
if ($request->user()) {
$response->header('Cache-Control', 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
$response->header('Pragma', 'no-cache');
$response->header('Expires', '0');
}
return $response;
}
2. ミドルウェアでの認証チェック強化
// app/Http/Middleware/AuthenticateWithInertia.php
public function handle(Request $request, Closure $next)
{
if (!$request->user()) {
if ($request->inertia()) {
return response()->json(['message' => 'Unauthenticated.'], 401);
}
return redirect()->route('login');
}
return $next($request);
}
3. Reactでの認証チェック
// resources/js/hooks/useAuth.ts
export function useAuth() {
const { auth } = usePage().props;
const navigate = useNavigate();
useEffect(() => {
if (!auth.user) {
navigate('/login');
}
}, [auth.user]);
return auth;
}
ベストプラクティス
多層防御アプローチを採用することで、より堅牢なセキュリティを実現できます:
セキュリティのチェックリスト
- キャッシュコントロールヘッダーの設定
- ミドルウェアでの認証チェック実装
- クライアントサイドでの認証状態監視
- エラーハンドリングの実装
- リダイレクト先の適切な設定
- セッションタイムアウトの設定
まとめ
ログアウト後のブラウザバック防止は、以下の3つのレイヤーで対策を実装することで、効果的に実現できます:
- キャッシュ制御:ブラウザのキャッシュ動作を制御
- サーバーサイドチェック:リクエスト時の認証状態を確認
- クライアントサイドチェック:UIレベルでの認証状態監視
これらの対策を組み合わせることで、セキュアなユーザー認証システムを構築できます。
Discussion