Introduction
Web Appは、認証した後にセッションを提供する
What is Session Management?
webappは各リクエストで、ユーザー名とパスワードを使用しない
しかし、HTTPプロトコルは本質的にはステートレス
HTTPプロトコルがリクエストごとに以前のリクエストの情報(状態)を保持しない
したがって、セッション管理はwebappの使用中にユーザーを追跡する目的で使われる
セッション管理ライフサイクル
この流れで行われる
- セッションの作成
- ユーザー名やパスワードなどの資格情報を入力した後にのみ発生すると思いこんでる
- 実際は、アプリケーションにアクセスしたときに初期セッションがすでにある
- 一部のアプリケーションが認証前でもユーザーのアクションを追跡する必要があるため
- セッショントラッキング
- セッション値を受け取ると、新しいリクエストごとに送信される
- これによって、HTTPがステートレスであってもユーザーのアクションを追跡できる
- リクエストが行われるたびに、Web アプリケーションはリクエストからセッション値を回復し、サーバー側でルックアップを実行して、セッションの所有者と権限を把握する
- セッション追跡プロセスに問題がある場合、攻撃者がセッションをハイジャックしたり、セッションを偽装したりする可能性がある
- セッションの有効期限
- HTTPプロトコルはステートレスなので、Web アプリケーションのユーザーが突然 Web アプリケーションの使用を停止することがある
- しかし、HTTPプロトコルはステートレスなので、Web アプリケーションには終了したことを発生したことを知る方法がない
- そのため、セッション値自体には有効期間が設定されている必要がある
- 有効期間が切れ、古いセッション値を Web アプリケーションに送信すると、セッションが期限切れになっているため、拒否される
- 再度認証するためにログイン ページにリダイレクトされ、セッション管理ライフサイクルが最初から行われる
- セッションの終了
- ユーザーが強制的にログアウト操作を実行することがある
- Web アプリケーションはユーザーのセッションを終了する必要がある
- セッションの有効期限切れに似ていますが、セッションの有効期間がまだ有効であっても、セッション自体を終了する必要があるという点で独特
- 終了プロセスに問題があると、脅威アクターがアカウントへの永続的なアクセスを取得できる可能性がある
Authentication vs Authorisation(認証と認可)
以下のそれぞれの頭文字をとって、IAAA(AAAプロトコル)
信頼のある認証システムに必要
rfc3539で定められてる
Identification(識別)
- 識別とは、ユーザーが誰であるかを確認するプロセス
- ユーザーが特定の ID であると主張することから始まる
- ユーザーIDもしくは、メールアドレス
Authentication(認証)
- 認証は、ユーザーが本人であることを確認するプロセス
- パスワードの入力、検証
Authorisation(認可)
- 特定のユーザーが要求されたアクションを実行するために必要な権限を持っていることを確認するプロセス
- すべてのユーザーがデータを表示できますが、データを変更できるのは一部のユーザーのみ、など
Accountability(計上)
- ユーザーが実行したアクションの記録を作成するプロセス
- ユーザーのセッションを追跡し、特定のセッションを使用して実行されたすべてのアクションをログに記録する必要がある
セッション管理とAAAプロトコル(IAAA)の関係性
- 認証(Authentication): セッションの作成方法に関与し、ユーザーを識別する役割を果たす。
- セッション値を付与する
- 承認(Authorisation): 特定のセッションに関連付けられたユーザーが、要求されたアクションを実行する権限を持っていることを確認する。
- 計上(Accountability): インシデント発生時に何が起こったのかを把握するために不可欠。
- リクエストがログに記録されることが重要。
- 各リクエストに関連付けられたセッションもログに記録する必要がある。
Cookies vs Tokens
セッションは、CookieとTokenの二つがある
それぞれに利点と欠点がある
そういえば、Cookieは廃止なんじゃないのかと思ったけど、
- 「Cookieが廃止された」の真相は「サードパーティーCookieの廃止」
- ファーストパーティーCookie(ログイン情報など)は今後も利用可能
- Google Chromeも2025年までに完全廃止予定
- 広告業界は「Privacy Sandbox」や「サーバーサイドトラッキング」に移行中
Cookie ベースのセッション管理
- セッションを管理する昔ながらの方法
- Web アプリケーションが追跡を開始すると、応答で Set-Cookie ヘッダー値が送信される
- ブラウザはこのヘッダーを解釈して、新しい Cookie 値を保存する
例
Set-Cookie: session=12345;
- ブラウザは session という名前のクッキーを 12345 という値で保存
- このクッキーはクッキーを受け取ったドメイン内で有効になる
- Set-Cookie ヘッダー追加の属性(オプション)も指定できる
- Secure
- クッキーは HTTPS接続 でのみ送信される。HTTP接続や証明書エラーがある場合、送信されない。
- HttpOnly
- クッキーは JavaScriptからの読み取りを禁止 される。
- Expires
- クッキーの 有効期限 を指定し、それが過ぎると削除される。
- SameSite
- CSRF攻撃を防ぐため、クロスサイトリクエストでクッキーが送信されるかどうか を制御する。
重要なポイント
- CSRF攻撃を防ぐため、クロスサイトリクエストでクッキーが送信されるかどうか を制御する。
- Secure
- ブラウザがクッキーの送信タイミングを自動で管理
- クッキーのドメインや属性を考慮し、クライアント側の追加コードなし でリクエストにクッキーを自動付与する
トークンを利用したセッション管理(Token-Based Session Management)
- トークンを利用したセッション管理は、比較的新しい方法
- ブラウザのクッキー管理機能を使わず、クライアント側のコード(JavaScriptなど) がセッション管理する
流れ
- 認証後、サーバーはトークンを発行し、リクエストボディに含めてクライアントに送信する。
- クライアント(JavaScript)がトークンを LocalStorage などに保存する。
- 新しいリクエストを送るとき、JavaScriptが LocalStorage からトークンを取り出し、ヘッダーに付与する。
- サーバーは送られたトークンを検証し、リクエストを処理する。
- 代表的なトークンの形式として JSON Web Token(JWT)がある。
- JWT は通常、リクエストの Authorization ヘッダーに Bearer トークン として送信される
例
JSON Web Tokenのフォーマット
Authorization: Bearer <トークン>
- トークンベース認証はブラウザの自動管理に依存しない
- 標準はあるものの、実装の自由度が高く、統一されたルールがないのが特徴。
まとめ
比較項目 | クッキー方式(Cookie-Based) | トークン方式(Token-Based) |
---|---|---|
認証情報の送信方法 | ブラウザが 自動でクッキーを送信 | クライアントが JavaScriptで手動で送信 |
セキュリティ | Secure 、HttpOnly 、SameSite 属性で保護可能 |
セキュリティ機能なし(適切な管理が必要) |
CSRF(クロスサイトリクエストフォージェリ) | 脆弱(ブラウザが自動で送るため攻撃されやすい) | 強い(LocalStorage は他のサイトからアクセス不可) |
CORS(クロスオリジンリクエスト) | 制限あり(SameSite や CORS 設定が必要) |
柔軟(どのドメインからでも送信可能) |
実装のしやすさ | 簡単(クライアント側の追加処理なし) | 複雑(トークン管理や手動での送信が必要) |
サーバーの状態管理 | セッション管理が必要(DBやメモリにセッションを保持) | ステートレス(Stateless)(サーバー側で状態を保持しない) |
分散アプリ・SPAとの相性 | 不向き(クッキーは特定ドメインに依存) | 適している(APIベースの認証に最適) |
認証情報の保存場所 | クッキー(ブラウザ管理) | LocalStorage / SessionStorage / メモリ |
使い分け
- モダンなAPI・SPA・マイクロサービス → トークン方式(JWT)
- サーバーレス&分散環境に適している
- CSRFに強く、CORSの制約が少ない
- 従来型のWebアプリ(セッション管理が必要) → クッキー方式
- セキュリティ強化が容易(
HttpOnly
、Secure
など) - クライアント側の実装がシンプル
- セキュリティ強化が容易(
トークン方式はAPIに最適、クッキー方式は従来型アプリに適している!
Securing the Session Lifecycle
-
セッションの作成に関する脆弱性
- 弱いセッション値: 推測可能なセッション値(例: Base64エンコードされたユーザー名)を使用すると、攻撃者にアカウントを乗っ取られる可能性がある。
- 制御可能なセッション値: JWTなどのトークンが適切に署名・検証されていないと、攻撃者が不正なトークンを作成できる。
- セッション固定攻撃: 認証前に発行されたセッションIDが、認証後もそのまま使用されると、攻撃者が事前に取得したセッションを利用して乗っ取ることができる。
- 安全でないセッション送信: SSOなどで認証情報をブラウザ経由で渡す際、攻撃者にリダイレクトURLを制御されると、セッションをハイジャックされるリスクがある。
-
セッションのトラッキングに関する脆弱性
- 認証バイパス: アクセス制御が不適切な場合、ユーザーが許可されていないアクションを実行できる。
- 垂直バイパス: 権限の高い操作を実行できる。
- 水平バイパス: 他のユーザーのデータを操作できる。
- 不十分なログ: どのユーザーがどのセッションでどの操作を行ったのかが記録されていないと、インシデント時に調査が困難になる。
- 承認されたアクションと拒否されたアクションの両方を記録することが重要。
- 認証バイパス: アクセス制御が不適切な場合、ユーザーが許可されていないアクションを実行できる。
-
セッションの有効期限に関する脆弱性
- 長すぎるセッションの有効期限: 長時間有効なセッションは、攻撃者に悪用されるリスクが高まる。
- セッションの使用場所の監視: セッションが異なる場所から使用された場合、ハイジャックの可能性を考慮し、強制終了する仕組みが必要。
-
セッションの終了に関する脆弱性
- セッションが適切に終了されない: ログアウト時にサーバー側でセッションが無効化されないと、攻撃者がハイジャックしたセッションを保持し続ける可能性がある。
- トークンの失効処理が不十分: 有効期間が埋め込まれたトークンは、即座に無効化できないため、ブロックリストを使用する必要がある。
- すべてのセッションの管理: ユーザーが現在のすべてのセッションを確認・終了できる仕組みがあると安全性が向上する。
- パスワードリセット時のセッション終了: パスワードリセットが成功した場合、すべての既存セッションを終了することが推奨される。