CyberFix Note
セキュアコーディング

セッション管理とセッションハイジャック対策。Cookie属性とセッションID再生成で不正利用を防ぐ設計

対象の目安: Webアプリ開発者と運用担当 / 実務

リク編集長 / セキュリティ全般・戦略
・ 約12分で読めます
セッション管理とセッションハイジャック対策。Cookie属性とセッションID再生成で不正利用を防ぐ設計

HTTPはリクエストごとに状態を持たないため、Webアプリはログイン後の利用者を識別するためにセッションIDを発行し、多くはCookieで受け渡します。このセッションIDが攻撃者の手に渡ると、パスワードを知られなくても本人になりすまされます。これがセッションハイジャックであり、防ぐ要点はIDを推測されない値で作り、盗まれにくいCookie属性で運び、権限が上がる場面で作り直し、使い終わったら確実に捨てる、という設計にあります。この記事は、それぞれの設定がなぜ効くのかという機構から順に整理します。

対象読者はWebアプリの開発者と運用担当です。扱う範囲はCookieベースのセッションID管理に絞り、生成、Cookie属性、セッション固定への再生成、寿命管理、ハイジャック経路への対応を解説します。記述はOWASP Session Management Cheat SheetとOWASP WSTG、MDN、IPA「安全なウェブサイトの作り方」の一次情報にもとづきます。検証は自組織が管理する環境に限って行う前提とし、攻撃の再現手順やペイロードは示しません。

セッションIDに求められる性質

セッションIDは、本人であることの証明書そのものとして働きます。したがって第三者が値を推測したり総当たりで当てたりできないことが最優先です。OWASPは、当て推量を防ぐためにセッションIDが少なくとも64ビットのエントロピーを持つべきだとしています。エントロピーとは実質的な当たりにくさの尺度で、値の一部が固定だったり連番だったりすると、見かけの長さより実質のエントロピーは大きく下がります。

この乱数は、暗号論的に安全な擬似乱数生成器(CSPRNG)で作ります。通常の乱数生成器は速度優先で、出力から次の値が予測されうるため、セッションIDには使いません。加えてIDには利用者名や連番などの意味を持たせず、サーバー側の実データと対応づけるだけの不透明なトークンにします。意味を持たせると、値からの推測や改ざんの手がかりを与えてしまうためです。

OWASPは、セッションIDに少なくとも64ビットのエントロピーを求め、CSPRNGで生成し、値自体に意味を持たせない不透明なトークンとすることを推奨しています。

実装では、こうした要件を満たしたフレームワーク標準のセッション機構を使うのが安全です。MDNも、セッション管理を自前で実装せず、評価の定まったフレームワークやライブラリに任せることを勧めています。自前実装は乱数の質やIDの寿命管理で見落としが生まれやすいためです。

Cookie属性で盗まれにくく運ぶ

生成したセッションIDは、Cookieの属性を適切に付けることで、運搬中や保存中の窃取リスクを下げられます。属性ごとに防ぐ相手が異なるため、役割を分けて理解します。

属性設定例機構と防ぐ相手
HttpOnlyHttpOnlyJavaScriptからのCookie読み取りを禁じ、XSSでのID窃取を緩和する
SecureSecureHTTPS接続に限って送信し、平文経路での露出を防ぐ
SameSiteSameSite=StrictクロスサイトからのリクエストにCookieを付けさせず、CSRFを抑える
Domain指定しない送信先ホストを限定し、サブドメインへの過剰な共有を避ける
PathPath=/送信対象のパスを限定する(機密性の保証ではない)

HttpOnlyは、document.cookieによるスクリプトからのアクセスを禁じます。仮にXSSが成立しても、この属性があればスクリプトからセッションIDを直接読み出せないため、窃取の主要な経路を一つ塞げます。ただしXSSそのものを許すとほかの被害は残るため、入力と出力の対策と併用します。

Secureは、Cookieを暗号化された経路すなわちHTTPSのリクエストにだけ載せます。これにより、通信を傍受する中間者が平文からセッションIDを拾う経路を断てます。SameSiteはクロスサイトのリクエストにCookieを付けるかどうかを制御し、Strictでは同一サイトのリクエストにしか送りません。

MDNは、SecureはHTTPSでのみ送信、HttpOnlyはスクリプトからのアクセス禁止、SameSiteはStrict、Lax、Noneの三値で、NoneはSecureとの併用が必須と説明しています。

SameSiteの選び方

SameSiteはStrictが最も堅い設定です。外部サイトからのリンクや遷移でもCookieを送らないため、CSRFへの効果が高くなります。一方で、外部からログイン後ページへ直接遷移した際にログイン状態が引き継がれないなど、体験に影響する場合があります。その場合はトップレベルの安全なナビゲーションでのみ送るLaxを最低ラインとします。NoneはCookieをクロスサイトでも送る設定で、単独では使えず、必ずSecureと併用します。

なお、SameSiteはCSRF対策を一枚上乗せする多層防御の一部です。サブドメインの扱いやブラウザ実装差の影響を受けるため、これ単独に頼らず、CSRFトークンなどアプリ側の対策と組み合わせます。CSRFの原理と対策の組み合わせは次の記事で詳しく整理しています。

あわせて読みたい

CSRFとは何か。仕組みからトークン・SameSite Cookieによる対策まで実務目線で解説

__Host- プレフィックスで固定する

Cookie名に__Host-を付けると、ブラウザはそのCookieに一定の条件を強制します。具体的にはSecure属性を持つこと、Domain属性を指定しないこと、Path=/であることが必須になります。Domainを指定しないホスト限定Cookieに固定されるため、あるサブドメインが侵害されても、そこからこのCookieを上書きしたり別ホストへ共有したりする経路を塞げます。

これらを組み合わせた、セッションIDの最も堅い設定例が次です。

Set-Cookie: __Host-SID=<token>; path=/; Secure; HttpOnly; SameSite=Strict

OWASP WSTGは、Cookie属性の検証項目としてSecureとHttpOnlyとSameSiteとDomainとPathを挙げ、推奨構成として Set-Cookie: __Host-SID=<session token>; path=/; Secure; HttpOnly; SameSite=Strict を示しています。

DomainとPathは最小化します。Domainを広く取ると、対象ドメイン配下の全サブドメインへCookieがひろがりID漏えいの面が増えます。PathはあくまでCookieをどのURLに送るかの制御であり、機密性を保証する仕組みではない点に注意します。

セッション固定への再生成

セッション固定(session fixation)は、攻撃者があらかじめ用意したセッションIDを利用者に使わせ、その利用者がログインした後に同じIDで乗り込む攻撃です。IDを盗むのではなく、あらかじめ知っているIDのまま権限だけ上がった状態を悪用する点が特徴です。

これを防ぐ機構が、権限レベルが上がる境界でのセッションIDの再生成(regenerate)です。OWASPは、認証の前後など権限レベルが変わったときにセッションIDを更新または再生成すべきだとしています。ログイン成功時に新しいIDを発行し、古いIDをサーバー側で無効化すれば、攻撃者が事前に握らせたIDは失効し、乗り込む足場を失います。

MDNは、セッション固定を防ぐためにログインのたびに新しいセッションIDを生成し、パスワード変更や普段と異なるログインなど高リスクなイベントではセッションを無効化することを挙げています。

再生成はログインだけでなく、権限が上がるあらゆる境界に適用します。たとえば一般利用から管理操作への昇格や、重要情報へのアクセス前の再認証時などです。再生成の際は、古いIDをクライアントに残さないよう、サーバー側のセッションを確実に破棄します。

セッションの寿命を管理する

セッションIDは長く生きるほど、盗まれたときに悪用できる時間が延びます。そこで寿命を二重に区切ります。一つはアイドルタイムアウトで、一定時間操作がなければセッションを失効させます。もう一つは絶対タイムアウトで、発行からの経過時間で強制的に失効させ、長期間有効なままのIDを残しません。

明示的なログアウトでは、Cookieを消すだけでなくサーバー側のセッションデータを破棄します。トークンの無効化はサーバー側で行うのが基本で、クライアントのCookieを削除しただけではサーバーに残ったセッションが有効なままになりうるためです。ログアウトやパスワード変更などの契機で、確実にサーバー側の状態を捨てる実装にします。

ハイジャック経路と対応の対応関係

セッションハイジャックには複数の経路があり、単一の設定ですべてを防ぐことはできません。経路ごとに効く機構を対応づけて、多層で守ります。

攻撃経路主な機構
XSSによるCookie窃取HttpOnlyと入力出力対策でスクリプトからの読み取りを防ぐ
ネットワーク傍受SecureとHTTPS全面化、HSTSで平文経路を残さない
CSRFSameSiteとCSRFトークンでクロスサイトの不正送信を防ぐ
セッション固定権限昇格時の再生成で事前に握らせたIDを失効させる

XSSはセッションID窃取の代表的な経路です。HttpOnlyでスクリプトからの読み取りを封じつつ、そもそもXSSを許さないよう出力エスケープなどの対策を土台に置きます。XSSの仕組みと対策は次の記事で整理しています。

あわせて読みたい

XSS(クロスサイトスクリプティング)の仕組みと対策。反射型・格納型・DOM型を原理から整理

ネットワーク傍受には、SecureでHTTPSに送信を限定し、サイト全体をHTTPS化してHSTSで常時HTTPS接続を強制します。これにより平文でセッションIDが流れる経路を残しません。CSRFはSameSiteとCSRFトークンの組み合わせで、固定は再生成で対応します。これらは互いの穴を補い合うため、どれか一つで足りるとは考えません。

サーバー側保持とステートレスの違い

ここまではサーバー側にセッションデータを持つ前提でした。これはセッションの無効化がサーバー側の破棄で完結するという利点があります。ログアウトや失効の要求に対して、該当セッションを即座に使えなくできます。

一方、JWTのようにクライアント側へ状態や権限を持たせる方式では、発行済みトークンの失効や無効化が難しくなります。トークン単体では有効期限まで検証を通ってしまうため、失効させるには失効リストの管理など追加の仕組みが必要になります。この違いと扱い方は次の記事で詳しく解説しています。

あわせて読みたい

JWTの仕組みと実装の落とし穴。署名検証とアルゴリズム混同を基礎から

IPA「安全なウェブサイトの作り方」は、セッション管理の不備を代表的な脆弱性の一つとして取り上げ、開発者と運営者向けに実装上の注意点を示しています。

実装チェックリスト

設計と実装を見直す際の確認項目を整理します。

  • セッションIDをCSPRNGで生成し、64ビット以上のエントロピーを確保しているか
  • セッションIDに利用者名や連番などの意味を持たせていないか
  • Cookieに HttpOnly と Secure を付与しているか
  • SameSite をStrict、少なくともLaxに設定し、NoneはSecure併用としているか
  • 可能な箇所で __Host- プレフィックスを使い、Domain指定なしとPath=/に固定しているか
  • DomainとPathを最小化し、不要なサブドメインへCookieを広げていないか
  • ログインなど権限が上がる境界でセッションIDを再生成し、古いIDを無効化しているか
  • アイドルタイムアウトと絶対タイムアウトを設定しているか
  • ログアウトやパスワード変更でサーバー側のセッションを破棄しているか
  • サイト全体をHTTPS化し、HSTSで常時HTTPS接続を強制しているか

セッション管理は、認証や認可と密接に関わります。誰であるかを確かめる認証と、何を許すかを決める認可の違いを踏まえると、セッションをどこで再生成し、どこで失効させるべきかの判断がつけやすくなります。認証と認可の違いは次の記事で整理しています。

あわせて読みたい

認証と認可の違い。Authentication と Authorization を基礎から整理する

出典・参考

この記事をシェア

関連する記事

セキュアコーディング

JWTの仕組みと実装の落とし穴。署名検証とアルゴリズム混同を基礎から

JWT(JSON Web Token)の構造と署名の役割を基礎から整理します。header.payload.signatureの3パート、HS256とRS256の違い、alg:noneやアルゴリズム混同といった検証まわりの落とし穴、有効期限と失効の設計、保存場所によるXSS/CSRFの注意点まで、一次仕様に沿って実装者向けに解説します。