Web認証の基本構造(ステートフル vs ステートレス)
Webアプリの認証は大きく「ステートフル」と「ステートレス」に分かれます。
セッションはサーバー側で認証状態を管理するステートフル方式、JWTはクライアント側に認証情報を持たせるステートレス方式です。
つまり、Session vs JWT の違いは「Cookieを使うかどうか」ではなく、「状態をどこで管理するか」の違いです。
セッション + Cookie
セッション認証は、ログイン後の認証状態をサーバー側で管理する方式です。
Webアプリでは最も古典的で、現在でも広く使われています。
仕組み
- ユーザーがログイン
- サーバーがセッションを生成
- セッションIDをCookieに保存
- リクエストごとにサーバーがセッションを照合
クライアントが保持するのは「セッションIDのみ」であり、実際のユーザー情報や認証状態はサーバー側に保存されます。
メリット
- サーバー側で即失効できる
- ログアウトやアカウント凍結が簡単
- 実装が比較的シンプル(フレームワーク標準対応が多い)
- 認証情報の実体をクライアントに持たせない
- セキュリティ運用がしやすい
デメリット
- サーバーが状態を持つ(ステートフル)
- 水平スケール時にセッション共有が必要
- CSRF対策が必要
- マルチクライアント(モバイル等)対応時にやや扱いづらい
向いているケース
- サーバーレンダリング中心のWebアプリ
- 管理画面
- 企業向け業務システム
- フルスタックフレームワーク利用時
JWT + Header
JWT + Header は、ログイン後の認証状態をトークンとしてクライアント側に保持する方式です。
サーバーは基本的に状態を持たず、リクエストごとにトークンを検証します。
仕組み
- ユーザーがログイン
- サーバーがJWTを発行
- クライアントがトークンを保持(LocalStorage / メモリなど)
- リクエスト時に
Authorization: Bearer <token>を付与 - サーバーが署名を検証
トークン自体にユーザー情報や有効期限が含まれており、サーバー側はセッションを保存しません(ステートレス)。
※ トークンの保存先は実装によって異なりますが、LocalStorage に保存すると XSS による窃取リスクが高くなるため注意が必要です。
メリット
- ステートレスでスケールしやすい
- マイクロサービスとの相性が良い
- モバイルアプリと自然に共存できる
- 原則としてCSRFの影響を受けにくい(Cookie自動送信がないため)
デメリット
- 発行後の即失効が困難
- 盗難時は有効期限まで基本有効
- 保存場所によってはXSSに弱い(LocalStorageなど)
- リフレッシュ設計が必要になりがち
- 設計を誤るとセキュリティ事故が起きやすい
向いているケース
- SPA + API構成
- モバイルアプリ連携
- マイクロサービス構成
- API中心のバックエンド設計
分散環境との相性が良く、スケールしやすいのが特徴です。
JWT + Cookie
JWT + Cookie は、JWTをCookieに保存して利用する方式です。
トークン自体はステートレスですが、送信方法はCookieベースになります。
仕組み
- ユーザーがログイン
- サーバーがJWTを発行
- JWTを HttpOnly 属性付きCookieに保存
- リクエストごとにCookieが自動送信される
- サーバーがJWTの署名を検証
トークンはクライアント側にありますが、サーバーはセッションを保持しません。
メリット
- ステートレス設計を維持できる
- HttpOnlyによりXSS耐性を高められる
- ブラウザ自動送信を利用できる
- SPA構成と相性が良い
デメリット
- 発行後の即失効は基本的に困難
- CSRF対策が必要(Cookieベースのため)
- 設計がやや複雑(Header方式より一段上)
- ブラックリスト管理をするとステートレス性が薄れる
向いているケース
- SPA + API構成(ブラウザ利用が前提)
- セキュリティを重視したフロントエンド設計
- Cookieベースの送信を利用したい場合
Header方式と異なり、HttpOnly を利用できるため、XSS対策を強めやすい構成です。
比較表
| 観点 | セッション + Cookie | JWT + Header | JWT + Cookie |
|---|---|---|---|
| CSRF耐性 | 弱い(対策必要) | 強い | 弱い(対策必要) |
| XSS耐性 | 強い(HttpOnly) | 保存場所次第 | 強い(HttpOnly) |
| 漏洩時の被害 | 即失効可能 | 有効期限まで有効 | 有効期限まで有効 |
| 強制ログアウト | 可能 | 原則不可 | 原則不可 |
| アカウント凍結反映 | 即時 | 遅延する可能性 | 遅延する可能性 |
| スケーラビリティ | やや弱い(メモリ内は弱い/共有すれば◎) | 強い | 強い |
| 設計の複雑さ | 低 | 中〜高 | 中〜高 |
使い分け
| 状況 | 向いている |
|---|---|
| ブラウザだけ(SPA含む) | セッション + Cookie |
| サーバーレンダリング中心 | セッション + Cookie |
| 管理画面・社内システム | セッション + Cookie |
| 小〜中規模Webサービス | セッション + Cookie |
| ブラウザ + モバイル | JWT + Header |
| 外部API公開 | JWT + Header |
| マイクロサービス | JWT + Header |
| オートスケール前提 | JWT(Header or Cookie) or セッション + Cookie + 共有ストア(Redis / DB) |
| ユーザー凍結・強制ログアウトを重視 | セッション + Cookie |
| 将来的に他サービスへ認証情報を渡す可能性あり | JWT |
迷ったらどう考えるか
- セキュリティ運用を最優先するなら → セッション + Cookie
- ブラウザ前提でSPAを作るなら → JWT + Cookie
- 外部APIやモバイルを前提とするなら → JWT + Header
まとめ
セキュリティ運用を重視するならセッション + Cookieは堅実な選択です。
一方で分散構成や外部連携を前提とする場合は、JWT(ステートレス設計)または共有セッション(Redis / DB)による状態共有が必要になります。
JWTは有力な選択肢ですが、保存方法や失効設計によって安全性は大きく左右されます。