Webアプリケーションにおけるセッション管理を、安全かつ運用しやすく設計・実装するための要点をまとめたものです。
目次
1. セッションIDの生成
| 項目 | 推奨 |
|---|
| 生成方法 | 暗号論的に安全な乱数生成器(CSPRNG)を使う |
| エントロピー | 64bit以上(実用上は128bit以上を推奨) |
| 中身 | 意味を持たない値にする(ユーザーID・時刻・連番などを含めない) |
| 自作 | 避ける。フレームワーク標準のセッション機構を使う |
- セッションIDの名前は
PHPSESSID や JSESSIONID などデフォルト名から変更し、使用技術を推測されにくくする。
- 推測可能な値(連番、タイムスタンプ、ユーザー名のハッシュなど)は使わない。
2. セッションIDの受け渡し
- Cookieで受け渡す。URLパラメータ(
?sid=...)やhiddenフィールドには載せない。
- URLに含めると、Refererヘッダ、ブラウザ履歴、アクセスログ、共有リンクから漏洩する。
- サーバー側は、自分が発行していないセッションIDを受け付けない(strict mode)。
3. Cookie属性
Set-Cookie: __Host-sid=<random>; Path=/; Secure; HttpOnly; SameSite=Lax
| 属性 | 目的 |
|---|
Secure | HTTPS通信でのみ送信する |
HttpOnly | JavaScriptから読めなくし、XSSによる窃取を防ぐ |
SameSite=Lax / Strict | クロスサイトリクエストでの送信を制限し、CSRFを緩和する |
Path | 必要な範囲に限定する |
Domain | 原則指定しない(サブドメインへの送信を防ぐ) |
__Host- プレフィックス | Secure・Path=/・Domainなしを強制し、サブドメインからの上書きを防ぐ |
Expires / Max-Age | セッションCookieは原則指定しない(ブラウザ終了で破棄)。「ログイン状態を保持」は別設計にする |
4. ライフサイクル管理
4.1 ログイン時の再生成(セッション固定攻撃対策)
- 認証成功時に必ずセッションIDを再生成する。
- 権限が変わるタイミング(管理者モードへの切り替え、パスワード変更、MFA完了など)でも再生成する。
- 古いセッションIDはサーバー側で確実に無効化する。
4.2 タイムアウト
| 種類 | 内容 | 目安 |
|---|
| アイドルタイムアウト | 最終操作から一定時間で失効 | 高リスク: 2〜5分 / 一般: 15〜30分 |
| 絶対タイムアウト | ログインから一定時間で強制失効 | 4〜8時間(業務アプリ)など用途次第 |
- タイムアウトはサーバー側で判定する(クライアント側のタイマーだけに頼らない)。
4.3 ログアウト
- サーバー側のセッションを破棄する(Cookieを消すだけでは不十分)。
- クライアントのCookieも削除する(
Max-Age=0)。
- 必要に応じて
Clear-Site-Data: "cookies", "storage" ヘッダを返す。
- ログアウトボタンはどの画面からも見つけやすい位置に置く。
4.4 強制失効
- パスワード変更・リセット時は、そのユーザーの他の全セッションを失効させる。
- ユーザーが自分のアクティブセッション一覧を確認し、個別にログアウトできる機能を提供する。
- 管理者がアカウント単位でセッションを強制失効できるようにする。
5. サーバー側のセッションストア
- セッションデータはサーバー側に保存し、クライアントにはIDのみを渡す。
- 保存先は Redis / DB など、複数台構成でも共有できるストアを使う。
- TTLをストア側にも設定し、期限切れデータが残らないようにする。
- セッションに保存するデータは最小限にする(パスワードやカード番号などは入れない)。
- セッションIDそのものをDBに保存する場合は、ハッシュ化して保存すると漏洩時の被害を抑えられる。
6. トークンベース(JWTなど)を使う場合
JWTは「ステートレス」が利点ですが、セッション管理として使う場合は以下に注意します。
- 失効が難しい:発行済みトークンを即時無効化できない。
- アクセストークンは短命(5〜15分)にし、リフレッシュトークンで更新する。
- リフレッシュトークンはサーバー側で管理し、ローテーション(使用ごとに再発行・旧トークン失効)と再利用検知を行う。
- 保存場所:
localStorage はXSSで読まれるため避け、HttpOnly Cookieに保存するのが無難。
- 署名検証:
alg: none を拒否し、許可するアルゴリズムを固定する。exp / iss / aud を必ず検証する。
- 機密情報をペイロードに入れない(署名されているだけで暗号化はされていない)。
- 「単一のWebアプリのログイン状態を保つ」だけなら、従来のサーバー側セッションの方がシンプルで安全なことが多い。
7. 関連する攻撃と対策
| 攻撃 | 対策 |
|---|
| セッションハイジャック(ID窃取) | HTTPS必須、Secure・HttpOnly、XSS対策、HSTS |
| セッション固定(Session Fixation) | ログイン時のID再生成、未発行IDの拒否 |
| CSRF | SameSite属性、CSRFトークン、Originヘッダ検証 |
| XSS経由のCookie窃取 | HttpOnly、出力エスケープ、CSP |
| ブルートフォースによるID推測 | 十分な長さのランダムID、異常アクセスのレート制限 |
| 共有端末での残存 | 適切なタイムアウト、ログアウト時の確実な破棄、Cache-Control: no-store |
8. 追加の防御策
- HTTPSを全ページで強制し、HSTS(
Strict-Transport-Security)を設定する。
- 認証後のページには
Cache-Control: no-store を付け、ブラウザやプロキシにキャッシュさせない。
- 重要操作(パスワード変更、送金、メールアドレス変更など)の前に再認証を求める。
- セッションと一緒にUser-Agentなどを記録し、急な変化があれば再認証を求める(IPアドレスはモバイル回線などで頻繁に変わるため、厳密な一致を条件にするのは慎重に)。
- 同時ログイン数の制限や、新しい端末からのログイン通知を検討する。
9. ログと監視
- 記録するもの:ログイン成功/失敗、ログアウト、セッション再生成、失効、タイムアウト、不正なセッションIDの受信。
- セッションIDそのものをログに出さない(出す場合はハッシュ化した値にする)。
- 不正なIDの大量送信、短時間での多地点アクセスなど異常パターンを検知・アラートする。
チェックリスト
参考資料