Skip to content

Instantly share code, notes, and snippets.

@kobitoDevelopment
Last active March 28, 2026 15:09
Show Gist options
  • Select an option

  • Save kobitoDevelopment/11d602f7bd198ba553cbcfee2adc7f05 to your computer and use it in GitHub Desktop.

Select an option

Save kobitoDevelopment/11d602f7bd198ba553cbcfee2adc7f05 to your computer and use it in GitHub Desktop.

httpOnly Cookie の誤解 ― 「読めない」は「悪用できない」ではない

よくある誤解

「Cookie を httpOnly にすれば JavaScript から読めないので安全」

半分正しく、半分間違い。httpOnly 属性は document.cookie 経由での読み取りを防ぐが、Cookie を読めなくても悪用できるという点が見落とされがち。

また、httpOnly は「Cookie 窃取による恒久的なセッションハイジャック(別端末からのログイン)」を防ぐ防具ではあるが、「今その瞬間、ユーザーのブラウザを操ること」は防げない。即死を避けるヘルメットであり、飛んでくる矢(XSS)そのものを防ぐ盾ではない。


攻撃パターン 1 ― CSRF(Cross-Site Request Forgery)

ブラウザには「リクエスト送信時に、対象ドメインの Cookie を自動的に付与する」という仕様がある。credentials: "include" を指定した fetch API も例外ではない。

攻撃者はこの仕様を利用して、Cookie の中身を一切知らないまま、被害者のブラウザに正規リクエストを送信させることができる。

攻撃の流れ

1. 被害者が target-site.com にログイン済み
   → セッション Cookie がブラウザに保存されている

2. 被害者が攻撃者の罠サイトを訪問する

3. 罠サイトの JavaScript が以下を実行する:

   fetch("https://target-site.com/api/password/reset", {
     method: "POST",
     credentials: "include",   // Cookie が自動送信される
     body: JSON.stringify({ newPassword: "attacker123" })
   });

4. ブラウザがセッション Cookie を自動で付与してリクエストを送信

5. サーバーは正規ユーザーからのリクエストと区別できず、
   パスワードが変更される → アカウント乗っ取り

攻撃者は Cookie の値を読む必要がない。 ブラウザに「送らせる」だけで目的を達成できる。


攻撃パターン 2 ― Session Riding(XSS との組み合わせ)

CSRF は「別サイトから」リクエストを飛ばす攻撃だが、XSS でサイト自身にスクリプトを注入された場合は別の問題が起きる

攻撃の流れ

1. 被害者が target-site.com にログイン済み

2. サイトに XSS 脆弱性があり、攻撃者のスクリプトが注入されている

3. 注入されたスクリプトが以下を実行する:

   fetch('/api/post_message', {
     method: 'POST',
     body: 'スパムURL'
     // credentials: "include" すら不要
     // 同一オリジン宛てなので Cookie は自動で付く
   });

4. ブラウザが httpOnly Cookie を自動で付与してリクエストを送信

5. サーバーは正規ユーザーからの投稿と見なし、スパムが送信される

これを Session Riding(セッションへの相乗り) と呼ぶ。

クロスオリジンではないため、SameSite 属性も CORS の設定も関係なくCookie は送信される。CSRF 対策を万全にしていても、XSS 脆弱性があれば同様の被害が起きる。


httpOnly が守れるもの・守れないもの

脅威 httpOnly で防げるか
XSS による Cookie の 読み取り・窃取 ✅ 防げる
CSRF による Cookie の 自動送信を利用した操作 ❌ 防げない
XSS + Session Riding による 同一オリジンへの不正操作 ❌ 防げない

httpOnly はあくまで XSS による Cookie 窃取 に対する緩和策であり、CSRF・Session Riding には無力。


CORS との関係

CORS はブラウザが レスポンスの読み取り を制御する仕組みであり、リクエストの送信自体を常に止めるわけではない。

  • (補足)Simple Request はクロスオリジンでも preflight なしに送信が通る点に注意。
  • Content-Type: text/plain などの条件を満たす Simple Request は、preflight(OPTIONS リクエスト)なしで本リクエストが送信される。
  • サーバー側で状態変更(パスワードリセットなど)が実行された後に、ブラウザがレスポンスをブロックするという順序になり得る。

CORS の設定が甘い場合(Access-Control-Allow-Origin: *Access-Control-Allow-Credentials: true の組み合わせなど)はさらに危険。

また、Session Riding(XSS 起因)は同一オリジンの問題なので CORS はそもそも無関係


正しい対策

httpOnly 単体では不十分。以下を組み合わせること。

0. XSS を防ぐこと(大前提)

Session Riding の根本対策は XSS 脆弱性をなくすこと。 HTML 出力時のエスケープ徹底、Content Security Policy(CSP)の設定など、スクリプト注入を許さない実装が前提となる。CSRF 対策をどれだけ積み上げても、XSS があれば同一オリジンから攻撃が成立する。

1. CSRF トークン

リクエストごとにサーバーが発行するランダムなトークンをリクエストに含め、サーバー側で検証する。攻撃者はトークンを知ることができないため、不正なリクエストを弾ける。

2. SameSite Cookie 属性

Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax
  • Strict ― クロスサイトからのリクエストには一切 Cookie を付与しない
  • Lax ― トップレベルナビゲーション(リンククリックなど)の GET のみ許可し、POST などには付与しない

3. CORS の厳密な設定

  • Access-Control-Allow-Origin にはワイルドカード (*) を使わず、信頼するオリジンを明示する
  • Access-Control-Allow-Credentials: true を使う場合は特に厳密に管理する

4. 重要操作での追加認証

パスワード変更などの高リスク操作では、現在のパスワードの再入力や多要素認証を要求することで、CSRF・Session Riding が成功しても被害を防げる。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment