セッションハイジャックの終焉:HttpOnly属性が守る「ブラウザの聖域」
多くのエンジニアが「XSS対策にはHttpOnlyを付ければいい」と教えられている。教科書的には正しい。だが、なぜそれが有効なのか、そして攻撃者がその「壁」を突破しようと試みる際、どのような低レイヤの攻防が繰り広げられているのか——そこまで理解している者は少ない。
今日は、CookieのHttpOnly属性を単なる設定項目としてではなく、ブラウザのメモリ空間と通信プロトコルが交差する「防衛の要塞」として再定義したい。
1. なぜ「JavaScriptからの隠蔽」が死活問題なのか
XSSが成功した時、攻撃者が真っ先に狙うのはdocument.cookieだ。これは、ブラウザのJavaScriptエンジン(V8など)が保有する実行コンテキストから、ユーザーのセッションIDを容易に引き出せることを意味する。
攻撃者の視点に立てば、これは極めて低コストな「認証情報の窃取」だ。本来、HTTP通信のステートフルネスを維持するためのセッションIDが、悪意あるスクリプトの一行で外部のC2サーバーへ送出される。このとき、攻撃者は単にCookieの内容を知るだけでなく、それを再利用(セッションハイジャック)して、正当なユーザーになりすます。
HttpOnlyは、この「JavaScriptの実行コンテキスト」と「ブラウザのCookieストレージ」の間に物理的(論理的)な断絶を強制する。
2. 低レイヤから見る防御メカニズム:ブラウザの責務
HttpOnlyフラグが付与されたCookieは、ブラウザ内部のCookie管理データベースにおいて、HttpOnlyビットが1に設定される。
- 通常のアクセス: ネットワークスタックがHTTPリクエストを構築する際、ブラウザはCookieストアを走査し、
HttpOnlyであろうとなかろうと、ドメインとパスの条件が合致すればCookieヘッダーに値を注入する。 - JSのアクセス:
document.cookieが呼ばれると、DOM APIはCookieストアへアクセスする。このとき、ブラウザのセキュリティポリシーにより、HttpOnlyビットが立っているエントリは、結果セットから「フィルタリング」される。
つまり、JavaScriptからは最初からそのCookieが存在しないかのように振る舞わされるのだ。これが、メモリ空間を汚染されたとしてもセッションIDが守られる根本的なメカニズムである。
3. 実践:セキュアなCookie設計と検証
単にHttpOnlyを付けるだけでは不十分だ。現代のWebアーキテクチャでは、以下の設定が「最低ライン」となる。
セキュアなCookie設定のHTTPヘッダー例
Set-Cookie: session_id=abc123xyz; HttpOnly; Secure; SameSite=Strict
- HttpOnly: JSからのアクセス禁止。
- Secure: 暗号化されたHTTPS通信でのみ送信。中間者攻撃(MITM)による平文漏洩を防ぐ。
- SameSite=Strict/Lax: CSRF対策。特に
Strictは、外部サイトからのリンク遷移時にもCookieの送出を抑制し、攻撃者が意図的にリクエストを発生させるシナリオを潰す。
サーバーサイドでの実装例(Go/net/http)
func setSecureCookie(w http.ResponseWriter, name, value string) {
http.SetCookie(w, &http.Cookie{
Name: name,
Value: value,
HttpOnly: true, // XSS対策の要。JSから隠蔽する
Secure: true, // TLS必須。MITMを防ぐ
SameSite: http.SameSiteStrictMode, // CSRF対策。厳格なドメイン制限
Path: “/”,
MaxAge: 3600,
})
}
4. 盲点:HttpOnlyは「銀の弾丸」ではない
ここで、セキュリティアーキテクトとして警鐘を鳴らしておきたい。HttpOnlyはセッションIDの窃取を防ぐが、XSSそのものを防ぐわけではない。
攻撃者は、セッションIDが盗めないと分かれば、以下のような戦術にシフトする。
1. アクションの実行(なりすまし): セッションIDを盗む代わりに、ログイン中のユーザーのブラウザ上でfetch()やXMLHttpRequestを使い、パスワード変更や送金などの「破壊的アクション」を裏で実行させる。
2. プロンプトインジェクションへの転用: 現在、フロントエンドに生成AIのチャットUIを組み込むケースが増えている。XSSでAIのコンテキストを汚染できれば、ユーザーの操作をAI経由で意図的に操作する「間接的なプロンプトインジェクション」が可能になる。
結論:多層防御への回帰
HttpOnlyは、現代のWebアプリケーションにおいて「必須の衛生管理」だ。だが、これだけで安心するのは、家の玄関に鍵をかけて満足しているのと同じだ。
真のセキュリティは、以下の組み合わせで完成する。
- CSP (Content Security Policy):
script-srcを厳格に制限し、そもそも悪意あるスクリプトが読み込まれないようにする。 - サニタイズ: サーバーサイドでの入出力バリデーション。
- セッションのライフサイクル管理: IPアドレスやUser-Agentの固定化、および異常なリクエストに対する再認証の要求。
我々エンジニアの仕事は、脆弱性をゼロにすることではない。攻撃者に「割に合わない」と思わせるだけの、堅牢でコストのかかる多層防壁を構築することにある。HttpOnlyはその第一歩であり、決してゴールではないことを忘れないでほしい。
コメント