Cookie・Sessionとセッション固定攻撃
アリスがapp.example.comへログインすると、ブラウザにはセッションIDを入れたCookieが届きます。攻撃者が先に知っているセッションIDをアリスに使わせた場合、ログイン後に同じIDが残ると何が起きるでしょうか。Cookie、Session、Secure、HttpOnly、SameSite、セッション固定攻撃を一つの時系列で学びます。以下のサービス、時刻、ログは架空です。
読む順序は、Cookieとサーバ側Sessionの違い→属性→正常ログインと固定攻撃→失効・復旧→演習です。科目B(午後)では『Cookieの属性を付けた』だけで済ませず、ブラウザがいつ送るか、サーバがどのセッションを受け入れるかを確認します。
1. Cookieは運搬手段、Sessionはサーバ側の状態
用語 | この事例での意味 |
|---|---|
Cookie | app.example.comが`Set-Cookie`でブラウザへ保存を指示し、条件が合うHTTP要求にブラウザが`Cookie`ヘッダとして返す値。Cookie自体を本人確認の結果として扱わない。 |
Session | サーバがランダムで推測困難なセッションIDに、利用者ID、認証時刻、失効時刻、必要な状態を対応付ける仕組み。この例のDB内部IDはintegerで、Cookie値の不透明な文字列とは別。 |
Secure | CookieをHTTPSなど安全な接続へ送る指定。HTTPでの送信漏れを防ぐための属性だが、端末上の窃取や悪性スクリプトの操作を全て防ぐものではない。 |
HttpOnly | JavaScriptの`document.cookie`から値を読めなくする属性。XSSが発生してもCookie値の直接読取りを難しくするが、同一サイト内で攻撃スクリプトが本人の権限で要求することまでは防げない。 |
SameSite | 異なるサイトから始まった要求へCookieを送る条件。Strict、Lax、Noneがある。CSRF対策の補助だが、同一サイトの別オリジンや一部の遷移には注意が必要。 |
セッション固定攻撃 | 攻撃者が知っているセッションIDを被害者に使わせ、そのIDがログイン後も有効なまま利用者の権限と結び付く欠陥。ログイン時のID再生成と旧ID失効が重要。 |
この例のCookie名は`__Host-session`、ホストは`app.example.com`です。ログイン後にサーバが新しい不透明な値S1を発行し、内部のセッション行(integer ID)へ対応付けます。ブラウザ側には利用者IDや権限を書かず、サーバ側で毎要求確認します。
HTTP/1.1 200 OK
Set-Cookie: __Host-session=S1; Path=/; Secure; HttpOnly; SameSite=Lax
GET /invoices/4101 HTTP/1.1
Host: app.example.com
Cookie: __Host-session=S1上のS1は説明用の短い値で、実際には暗号学的に安全な乱数から推測困難な長さで作ります。`__Host-`接頭辞ではSecure、Path=/、Domain属性なしが必要です。`Path=/`はブラウザが全パスへ送る範囲を表しますが、サーバ内の認可境界にはなりません。
2. Cookie属性の効く場所と効かない場所
属性 | 役割・落とし穴 |
|---|---|
Secure | HTTPS接続時の送信に制限する。最初のHTTPアクセスをHTTPSへ転送するだけでは十分でない場合があり、HSTSやHTTPを受けない構成も検討する。 |
HttpOnly | JSからCookie値を読めなくする。XSSの悪性コードが画面やAPIを操作できる可能性は残るため、XSSそのものの修正が必要。 |
SameSite=Strict | クロスサイトの要求へ送らない方向の強い制限。外部リンクからの通常遷移でログイン状態が見えない場合があり、UXと設計を確認する。 |
SameSite=Lax | 一般的なクロスサイトのサブリソースやPOSTでは制限するが、トップレベルの安全なナビゲーション等では送られ得る。CSRF対策の全てではない。 |
SameSite=None | クロスサイト送信を許す。Secureが必要。外部埋込みなど用途を限定し、CSRF対策と第三者Cookieの制約を考える。 |
Domain | 指定すると通常は対象ドメインのサブドメインにも送られる。不要なら省きホスト限定にする。弱いサブドメインからのCookie設定・衝突を避ける。 |
Path | 送信するパスを絞る条件であり、同じホスト上のアプリ間の強い分離境界ではない。`__Host-`ではPath=/が必須。 |
Max-Age / Expires | ブラウザ側の保持期間。サーバ側セッションの絶対期限・無操作期限とは別。Cookieを削除しても盗まれたS1のサーバ側状態は残り得る。 |
SameSiteの『site』は通常、スキームと登録可能ドメインを基準とし、オリジンのホスト名だけで決まりません。`evil.example.com`と`app.example.com`は別オリジンでも同一サイトと扱われる場面があります。信頼できないサブドメインがある場合、SameSiteだけでCSRFを防ぐと考えないでください。
3. 正常なログインではIDを切り替える
未ログインのブラウザが匿名セッションS0を持っていても、APP-1はそれを認証済みとして扱わない。ログイン要求ではパスワードなどを確認する。
認証に成功したら、新しい推測困難なセッションID S1を発行する。S0を無効化し、S1をアリスの認証済み状態と結び付ける。
`Set-Cookie`でS1を配り、後続要求ではS1の有効性・期限・利用者状態をサーバ側で照合する。S0や未知のIDを受け入れない。
ログアウト、パスワード変更、権限昇格・MFA完了などの境界で必要に応じてIDを再生成し、旧IDを無効化する。ブラウザのCookie削除とサーバ側失効を両方行う。
S0は匿名用、S1は認証後。S0をそのまま昇格させない。
S0を削除せずにS1だけ作ると、S0が依然アリスへ結び付く実装では攻撃が成立します。逆にS0を失効しても、認証前の別経路で任意のセッションIDを受け入れる実装が残れば再発します。`Set-Cookie`の送信とサーバ側状態を両方確認します。
4. セッション固定攻撃の成立条件
攻撃者は何らかの方法でアリスのブラウザに自分の知っているS0を使わせる必要があります。URLにセッションIDを載せる旧実装、サブドメインからのCookie設定、任意の未発行IDをサーバが採用する実装などが入口になります。攻撃者がS0を知るだけでは、アリスがそれを使わなければ成立しません。
時点 | 脆弱な動作/正しい動作 |
|---|---|
攻撃準備 | 攻撃者がS0を取得・注入する。`__Host-`やDomain省略はサブドメインからのCookie上書きを抑えるが、全ての入口を塞ぐわけではない。 |
アリスがログイン | 脆弱な実装はS0の行へuser=aliceを追加する。正しい実装は新S1を発行し、S0を失効する。 |
攻撃者がS0を送る | 脆弱な実装ならアリスとしてアクセスできる。正しい実装ならS0は無効なので拒否する。 |
調査で見る証拠 | ログイン直前・直後のセッション識別子を安全な監査用IDで比較し、旧IDの失効時刻と要求の成否を確認する。生のCookie値をログへ出さない。 |
架空ログでは、生のCookie値ではなく監査用の短い識別子だけを表示します。セッションIDをそのままアクセスログに残すと、ログ閲覧者がセッションを再利用し得ます。`old=revoked`と`new=active`を分けて記録します。
15:00:00 login user=alice pre_session=SID-0
auth=ok rotate=ok old=revoked new=SID-1
15:00:01 request session=SID-0 action=deny
reason=revoked
15:00:02 request session=SID-1 action=allow
user=alice path=/invoices/4101`SID-0`が拒否された事実は、このアクセス経路で旧IDが使えないことを示します。すべてのAPIやサーバ群で失効が反映されたかは別の確認が必要です。セッション保管先が分散している場合は、失効の伝播遅延と古いキャッシュを調べます。
5. 盗難・CSRF・XSSとの違い
事象 | 主な成立条件と対策の位置 |
|---|---|
セッション固定 | 攻撃者が既知IDを被害者に使わせ、ログイン後も同じIDが有効。ログイン時のID再生成、旧ID失効、未知ID拒否を確認する。 |
セッション盗難 | 認証済みS1を後から盗む。Secure、HttpOnly、端末・ログの保護、短い期限、サーバ側失効などを組み合わせる。ID再生成だけでは盗難後の不正利用を止め切れない。 |
CSRF | 被害者のブラウザに意図しない要求を送らせる。SameSiteは補助であり、状態変更APIにはCSRFトークンやOrigin検証を適用する。 |
XSS | 同一オリジンで悪性スクリプトが動く。HttpOnlyでCookieの直接読取りを防いでも、本人としてAPI要求を出せる場合がある。入力・出力処理やCSPも必要。 |
Cookieの値をサーバ側へそのまま信じて、`role=admin`などの権限情報を改ざん可能なCookieに保存すると、セッション固定以前に権限改ざんの問題になります。署名付きCookieを使う構成でも、失効、鍵漏えい、権限変更の反映を別途設計する必要があります。
6. 期限・変更・障害時の運用
無操作期限と絶対期限をサーバ側で持つ。ブラウザのMax-Ageだけでは、盗まれたセッション値の再利用を止められない。
権限変更やMFA完了で必要な場合はセッションIDを再生成する。旧IDの失効と新IDへの権限反映を同時に確認する。
ログアウトではCookieを削除し、サーバ側セッションも失効する。削除ヘッダは元Cookieと同じName・Domain・Pathのスコープで送る。
セッション保管先障害時に『検証できないIDを許可』へ落とさない。復旧時は古いセッションが復活しないか、失効時刻とバックアップを確認する。
サブドメインやリバースプロキシの変更時はCookieのDomain、Path、Secure属性、HTTPS終端、重複Cookieの解釈を確認する。
セッション値の漏えいが疑われた場合は、該当セッションと必要なら同じ利用者の全セッションをサーバ側で失効し、ログイン履歴、利用端末、重要操作を調査します。Cookieだけを削除しても攻撃者が持つコピーは消えません。パスワード再設定が必要かは侵入経路によります。
6-1. ブラウザが送る条件を一要求ずつ確認する
ブラウザの状況 | __Host-sessionを送るかの判断 |
|---|---|
https://app.example.com/invoices/4101 | 同じホストでHTTPS、Path=/に合うため送る。APP-1は受信後にサーバ側の有効性と権限を判定する。 |
http://app.example.com/invoices/4101 | Secureにより通常は送らない。HTTPをHTTPSへ転送しても、最初のHTTP要求にセッション値を載せる設計にしない。 |
https://api.example.com/ | Domainを指定しない__Host-sessionはapp.example.com専用なので送らない。APIを別ホストに移すなら認証設計を再検討する。 |
他サイトからのトップレベルGET | SameSite=LaxではCookieが送られ得る。GETに状態変更を実装しない。 |
他サイトからのPOST | SameSite=Laxで通常は送られない方向だが、ブラウザ差や同一サイト別オリジンを考慮し、CSRF対策を別に持つ。 |
Cookieは同じ名前でもDomainやPathが違えば複数保存され、要求に複数値が届く場合があります。APP-1のパーサがどちらを採用するかに依存したままにせず、重複や不正形式を拒否する方針を確認します。`__Host-`でホスト限定にすると、広いDomain属性の上書きや衝突を抑えやすくなります。
6-2. 失効と再生成を分散環境で成立させる
APP-1が複数ノードで動く場合、ログインしたノードだけでS0を失効しても、別ノードが古いキャッシュでS0を受け入れる可能性があります。共有Session保管先、失効イベントの伝播、キャッシュTTLを設計し、全ノードへS0の拒否が反映された時刻を確認します。
無操作期限は最後の有効要求から数え、絶対期限はログイン時刻から数える、とこのサービスでは定義します。要求のたびに無操作期限だけを延ばしても絶対期限は延ばしません。権限の高い操作には再認証を求める方針も設けます。期限切れ判定はブラウザ時計ではなくサーバの時刻で行います。
6-3. 侵害疑いから再開まで
S1が漏れた疑いの根拠、利用者、監査用セッションID、発生・検知時刻を保全する。生のCookie値を報告書へ貼らない。
対象S1をサーバ側で失効し、利用者の全セッション失効が必要か判断する。Cookie削除ヘッダも送り、次の要求で旧IDが拒否されることを確認する。
同じIDからの異常なIP・端末・重要操作を調べる。IPだけで攻撃者と断定せず、VPN、モバイル回線、NATを考慮する。
固定攻撃ならS0の注入経路、ログイン時の再生成、旧ID失効、全ノードへの伝播を修正する。盗難なら漏えい経路も別に修正する。
正規利用者が新S2でログインでき、S0とS1は全APIで拒否され、重要操作の監査が回復したことを確かめて再開する。
セッション固定が疑われた場合、攻撃者が知るS0から実際に業務APIへ成功したかを調べます。S0での認証成功ログだけでは、攻撃者による利用を証明できません。反対にアクセスログにS0がないだけでも、ログの収集範囲や保持期間が不足していれば利用なしとは断定できません。
7. 科目B(午後)の判断と演習
演習1:ログイン後もS0
条件:S0でログインし、そのままアリスの権限へ昇格した。質問:何を直すか。解答:新しいS1を発行してS0を失効する。誤答『Secureを付ける』は送信先を制限するだけで固定攻撃を解消しない。
演習2:HttpOnly
条件:CookieにHttpOnlyを付けた。質問:XSSが発生しても完全に安全か。解答:安全ではない。Cookie値のJS読取りは抑えるが、同じオリジンのAPI操作は残り得る。誤答はHttpOnlyの範囲を広げすぎている。
演習3:SameSite=Lax
条件:状態変更APIをSameSite=Laxだけで守る。質問:CSRF対策として十分か。解答:十分でない。Origin確認やCSRFトークンを併用する。誤答は同一サイト別オリジン等の条件を無視している。
演習4:Domain属性
条件:通常名のSession Cookieをapp.example.comから`Domain=example.com`で設定した。質問:何が広がるか。解答:サブドメインへの送信・設定の影響範囲。不要ならDomainを省く。`__Host-`名ならDomain付きCookieはブラウザに拒否される。誤答『Pathだけで分離』は送信スコープを混同する。
演習5:ログアウト
条件:ブラウザのCookieを削除したが、サーバのS1は有効。質問:攻撃者がS1を持っていたら使えるか。解答:使える可能性がある。サーバ側の失効が必要。誤答『Cookie削除で全て無効』は別ブラウザのコピーを忘れている。
演習6:復旧後の旧ID
条件:障害復旧で古いSession DBを戻した。質問:何を試験するか。解答:失効済みS0やログアウト済みS1が再び受理されないこと。誤答『ログイン成功だけ確認』は失効の巻戻しを見落とす。
8. 一次資料
この記事についてAIに深掘り質問する
ChatGPT、Claude、Perplexityにこの記事を参照させ、要点の確認や疑問点を自由に質問できます。
次におすすめの学習
編集・検証について
編集・検証:IT資格ラボ編集部
IPAが公開する試験要綱・シラバス・過去問題と、各技術の公式資料を優先して内容を確認しています。制度変更や誤りを確認した場合は、記事を見直して更新します。
編集方針・情報源・訂正方針を見る