Open3

Cookieでセッション管理するときに知っておきたいこと

Fujiya228Fujiya228

CookieにアクセスできるJSのコードの条件

JavaScript から document.cookie を使ってクッキーにアクセス(読み書き)するためには、主に以下の条件を満たす必要がある

  1. HttpOnly フラグが付与されていないこと

    • HttpOnly が付いているクッキーは、JavaScript 側からは一切読めない。
    • 例:Set-Cookie: session=…; HttpOnly → JS からは不可
  2. ドメイン/パスの一致

    • クッキーの Domain 属性に指定されたドメイン(例:.example.com)か、そのサブドメイン(例:app.example.com)でなければアクセスできない。
    • クッキーの Path 属性(例:/foo/)が現在のページのパス(例:/foo/bar.html)のプレフィックスになっている必要がある。
  3. セキュア環境(Secure フラグ)

    • Secure 指定のあるクッキーは、HTTPS(https://)でロードされたページでのみ読み書き可能。
    • HTTP(http://)では見えない。
  4. SameSite ポリシー

    • SameSite=StrictLax の場合、クロスサイトの文脈(iframe 埋め込みや外部リンククリック)で送信・参照が制限される。
    • SameSite=None; Secure を設定していないと、第三者コンテキストではそもそもクッキーがブラウザに送られず、JS からも見えない。
  5. 同一オリジン(Same‑Origin Policy)

    • プロトコル(http/https)、ホスト、ポートの組み合わせが完全に同一である必要がある。
    • 例:https://example.com:443 上のスクリプトは、同じオリジンのクッキーしか操作できない。
  6. ブラウザのプライバシー設定

    • サードパーティークッキー全般をブロックしている場合、iframe 内などの第三者コンテキストではクッキー自体が利用できず、JS からの参照も不可になる。

例:JavaScript での読み書きコード

// 書き込み(有効期限7日、Secure/SameSite=Lax)
document.cookie = "user=alice; Path=/; Max-Age=" + (7*24*3600) + "; Secure; SameSite=Lax";

// 読み込み
console.log(document.cookie);  // HttpOnly 以外の、自ドメインかつパス一致のクッキー一覧が文字列で返る

―以上が、JS でクッキーにアクセスする際の主要な条件。

Fujiya228Fujiya228

Cookieでセッション管理しているサービスで、セッションを盗まれるパターン

セッションを盗まれる(セッションハイジャックされる)代表的なケースと、その要因は大きく次のとおり。


1. ネットワーク上の盗聴(サイドジャッキング/MITM)

  • HTTP 送信:Secure 属性のないクッキーを平文の HTTP 経路で送ると、パケットキャプチャ(Wi‑Fi の盗難アクセスポイントなど)で抜き取られる。
  • 対策:常に HTTPS を使い、クッキーに Secure; HttpOnly を付ける。

2. クロスサイトスクリプティング(XSS)

  • スクリプト実行:サイトに脆弱性があり、攻撃者が悪意のある JavaScript を注入すると、document.cookie でクッキーを読み取り外部送信できる。
  • 対策:入力値の厳格なサニタイズ/エスケープ、Content Security Policy(CSP)の導入、クッキーに HttpOnly 属性を必ず付与。

3. セッション固定攻撃(Session Fixation)

  • 初期セッションの押し付け:攻撃者が予め用意したセッション ID(固定されたクッキー)を犠牲者に使わせ、認証後もそのまま同じ ID を使わせる。
  • 対策:ログイン時に必ずセッション ID を再生成し(セッションリジェネレーション)、既知のセッション ID は無効化。

4. クロスサイトリクエストフォージェリ(CSRF) ※直接盗むわけではないが…

  • 権限の横取り:被害者がログイン済み状態で、別サイトから不正なリクエストを飛ばされることで、被害者のセッション権限を悪用される。
  • 対策:トークン(CSRF トークン)や SameSite 属性で外部サイトからの不正送信を防止。

5. 物理/クライアントマシン上のマルウェア

  • マルウェア感染:キーロガーやブラウザプラグイン型マルウェアが、ローカルに保存されたクッキーを抜き取る。
  • 対策:端末のウイルス対策、不要プラグインの排除、短めの有効期限設定。

6. ログ/バックアップからの露出

  • サーバー側ログ:デバッグやアクセスログに誤ってクッキー(セッショントークン)を記録し、そのバックアップが流出。
  • 対策:ログに機密情報を残さない、トークンはマスクやハッシュ化して記録。

まとめとベストプラクティス

  1. HTTPS + Secure 属性
  2. HttpOnly 属性 で JS アクセスを制限
  3. SameSite=strict or Lax でクロスサイト侵害を抑止
  4. SSO・多要素認証 の併用
  5. セッション固定対策(ログイン時の ID 再生成)
  6. 入力のサニタイズ/CSP で XSS を防ぐ
Fujiya228Fujiya228

CSRFの具体的な流れ

以下は、典型的な CSRF(Cross-Site Request Forgery)の攻撃がどう行われるかをステップごとの示したもの。


  1. 被害者が正規サイトにログイン

    • ブラウザで https://bank.example.com にアクセスし、ID/PW を入力。
    • サーバーは応答ヘッダで Set-Cookie: session=ABC123; Secure; HttpOnly; SameSite=Lax を返し、以降のリクエストに自動で添付されるようになる。
  2. 被害者はログイン状態のまま別サイトへ移動

    • 例:https://evil.attacker.com を開く(あるいは広告経由でロードされる iframe)。
    • この時点でブラウザにはまだ bank.example.com のセッション Cookie が保持されているが、正規フォームを送信してはいない。
  3. 攻撃者側が不正リクエストを準備

    • HTML の <img> タグや <form> の自動送信スクリプトで、被害者の銀行口座から第三者へ送金するリクエストを仕込む。
    <!-- GET リクエストの場合の例 -->
    <img src="https://bank.example.com/transfer?to=attacker&amount=1000" />
    
    <!-- POST 自動送信フォームの場合の例 -->
    <form id="csrf" action="https://bank.example.com/transfer" method="POST">
      <input type="hidden" name="to" value="attacker">
      <input type="hidden" name="amount" value="1000">
    </form>
    <script>document.getElementById('csrf').submit();</script>
    
  4. ブラウザが自動的に Cookie を付与してリクエスト送信

    • <img><form> がロード/submit されると、同一オリジンポリシーにより bank.example.com の Cookie(session=ABC123)が自動でヘッダに乗る。
    • 被害者は何も操作していないのに、ログイン中の銀行サイトへ不正リクエストが飛ぶ。
  5. サーバー側が正当なリクエストと判断して処理

    • サーバーは「認証済みユーザーからのリクエスト」と見なし、攻撃者指定の口座へ 1,000円振り込む処理を実行。
  6. 被害に気づきにくい

    • 振込完了後も被害者画面には何も表示されず、バランス照会ページを見るまで異変に気づかない。

補足

悪意あるサイト(evil.attacker.com)がユーザーのセッション Cookie を直接「読み取る」わけではない。ブラウザの仕組みを利用して、あたかも正規サイトに「ユーザー自身」がアクセスしたように振る舞わせ、ブラウザが自動的に Cookie を付与して送信してしまう、というのが CSRF の本質。以下ポイント。

  1. Same-Origin Policy(SOP)で読み取りは不可

    • evil.attacker.com 上の JavaScript が document.cookiebank.example.com の Cookie を参照したり、値を盗み出したりすることはできません。
    • SOP により、スクリプトは自分と同じオリジン(プロトコル+ホスト+ポート)の Cookie にしかアクセスできないからです。
  2. ブラウザが自動で Cookie を付与する仕組みを悪用

    • Cookie は、その DomainPath 条件に合致するリクエストを行うと、ブラウザが必ずヘッダに載せて送信します(たとえクロスサイトの埋め込みリクエストでも)。

    • たとえば攻撃者ページに以下のような HTML を置くと――

      <!-- GET リクエスト例:画像読み込み -->
      <img src="https://bank.example.com/transfer?to=attacker&amount=1000" />
      

      ――ブラウザは自動的に Cookie: session=ABC123; … をヘッダに付けて bank.example.com にリクエストを投げます。

  3. 重要:攻撃者はレスポンスも Cookie の中身も見えない

    • <img> タグでリクエストを仕込んでも、攻撃者側の JavaScript からはレスポンスの中身も、Cookie の値も一切読めません。
    • しかしサーバー側(銀行)は「あ、このセッションは認証済みユーザーからのリクエストだ」と判断して振込処理を行ってしまいます。
  4. POST フォームを自動 submit しても同様

    <form id="csrf" action="https://bank.example.com/transfer" method="POST">
      <input type="hidden" name="to"     value="attacker">
      <input type="hidden" name="amount" value="1000">
    </form>
    <script> document.getElementById('csrf').submit(); </script>
    

    -- ブラウザはフォーム送信時にも該当ドメインの Cookie を添付します。


補足まとめ

  • 攻撃側は「ブラウザに正規サイト向けリクエストをさせる」だけ
  • ブラウザが持つ Cookie の自動送信機能(DomainPath マッチ)を利用し、ユーザーの意図しないリクエストを行わせる。
  • 攻撃者側が Cookie の値を読むことはできませんが、サーバーはあくまで「有効なセッション付きリクエスト」として処理してしまうため被害が起こります。

防御策サマリ

  • CSRF トークン
    • フォームにランダムなトークンを埋め込み、サーバー側で照合
  • SameSite=strict または Lax
    • クロスサイトからの Cookie 送信を制限
  • Double Submit Cookie
    • Cookie とリクエストボディ両方に同一のトークンを載せて検証
  • Referer/Origin ヘッダ検査
    • リクエスト元が自ドメインかをサーバー側でチェック