Claude Media
Claude CodeでセッションCookieとCSRF対策を点検 — 属性・再発行・失効

Claude CodeでセッションCookieとCSRF対策を点検 — 属性・再発行・失効

HttpOnly・Secure・SameSiteの設定、ログイン時のセッションID再発行、ログアウト時のサーバー側失効、CSRFトークンの有無を、読み取り専用の調査でClaude Codeに点検させる手順です。

セッションCookieの点検は、見る場所が決まっています。Set-Cookieの属性、ログイン時にセッションIDが替わるか、ログアウトでサーバー側のセッションが消えるか、状態を変えるリクエストにCSRF対策があるか。この4点です。コードを横断して探す作業なので、Claude Codeに読み取り専用で任せる価値があります。

この記事では、点検の観点をOWASPのチートシートから絞り、Claude Codeへの頼み方、権限の設定、結果の読み方まで順に示します。

点検する4つの観点

OWASPのSession Management Cheat Sheetは、Cookieで運ぶセッションIDに使う属性を個別に説明しています。CSRF Prevention Cheat Sheetは、トークンやヘッダー検証を組み合わせる前提で書かれています。この2本から、コードで確かめられる項目を拾います。

点検項目

コードで確かめる4観点

  • Cookie属性

    Secure、HttpOnly、SameSite、__Host-接頭辞、Domain属性を確認します。

  • ログイン時の再発行

    認証で権限が変わる時点で、セッションIDが新しくなっているかを見ます。

  • ログアウトと期限

    ログアウトでサーバー側のセッションが破棄され、アイドルと絶対の期限がサーバーで効くかを見ます。

  • CSRF対策

    状態を変えるエンドポイントがトークンまたはヘッダー検証で守られ、GETで状態を変えていないかを見ます。

Cookie属性は何を見ればよいか

属性ごとに、何を防ぎ、何を防がないかが違います。点検の判断に必要な範囲を表にします。

属性防ぐもの点検での見方
Secure防ぐものHTTPでのセッションID送出点検での見方付いていなければ指摘
HttpOnly防ぐものXSSによるdocument.cookieからの読み出し点検での見方付いていなければ指摘
SameSite防ぐものクロスサイト要求でのCookie送信点検での見方StrictかLaxを明示しているか
__Host-接頭辞防ぐものサブドメインからの偽造、HTTPSダウングレード点検での見方セッションIDに推奨

HttpOnlyは万能ではありません。OWASPは、XSSとCSRFが組み合わさった場合、リクエストにはブラウザーがセッションCookieを自動で付けると説明しています。HttpOnlyが守るのはCookieの機密性だけです。XSSが成立している状況で、攻撃者がCookieを持ち出して使う道は塞げても、ブラウザー越しに操作される道は塞げません。

SameSiteの扱いにも注意があります。OWASPは、セッションCookieにはSameSite=Strict(推奨)かLaxを明示し、ブラウザーの既定値には頼らないよう求めています。SameSite=NoneをSecureなしで使うことも禁じています。Domain属性は付けず、発行元のホストだけに送る形が推奨です。

接頭辞つきの例は次の形です。

Set-Cookie: __Host-SessionID=<value>; Secure; HttpOnly; SameSite=Strict; Path=/

フレームワークの既定値を知っておく

既定値は、フレームワークごとに違います。Claude Codeに「既定のままか、明示しているか」を分けて報告させるには、点検側もこの差を知っている必要があります。

項目Djangoexpress-session
HttpOnlyDjangoSESSION_COOKIE_HTTPONLYの既定はTrueexpress-sessioncookie.httpOnlyは既定で設定される
SameSiteDjangoSESSION_COOKIE_SAMESITEの既定は'Lax'express-sessioncookie.sameSiteの既定はfalse(属性なし)
SecureDjangoSESSION_COOKIE_SECUREの既定はFalseexpress-sessioncookie.secureはtrueを推奨(要trust proxy)
CSRF用CookieDjangoCSRF_COOKIE_SAMESITEの既定は'Lax'express-session組み込みなし。別途ミドルウェアが必要

expressの表で、SameSiteの既定がfalseになる点は見落としやすい部分です。公式ドキュメントでは、cookie.sameSiteの既定はfalseで、trueにするとStrictになります。リバースプロキシの背後でsecure: trueを使うなら、app.set('trust proxy', 1)が必要だとも書かれています。

Djangoは逆で、Secureだけが既定でFalseです。本番設定でSESSION_COOKIE_SECURE = Trueを明示しているかどうかが、点検の最初の確認点になります。

ログイン時のセッションID再発行

OWASPは、権限の水準が変わる時点でセッションIDを再発行するよう定めています。代表例は認証で、パスワード変更や管理者への切り替えも同じ扱いです。再発行しないと、攻撃者が被害者のブラウザーにセッションIDを仕込むセッション固定攻撃が成立します。

フレームワーク別の再発行の呼び出しは、公式の説明では次のとおりです。

  • express-session: req.session.regenerate(callback)を認証成功後に呼ぶ
  • PHP: session_start()の後にsession_regenerate_id(true)
  • J2EE: request.getSession(true)とHttpSession.invalidate()
  • ASP.NET: Session.Abandon()と新しいCookieの発行

Claude Codeに探させるのは、ログイン処理の中に上のような呼び出しがあるかどうかです。無いままreq.session.userId = user.idだけで済ませていれば、指摘対象になります。

もう一点、OWASPは「未発行のセッションIDを受け付けない」厳格な方式を求めています。PHPは既定が寛容な方式だと明記されているため、PHPのコードでは設定の確認も加えます。

ログアウトと期限はサーバー側で効いているか

Cookieを消すだけでは、盗まれたセッションIDは無効になりません。OWASPは、ログアウト時もセッション期限切れの時も、サーバー側でHttpSession.invalidate()やsession_destroy()のような破棄を呼ぶことを必須としています。

期限は2種類あります。

  • アイドル期限: 最後のリクエストからの無操作時間。目安は高価値のアプリで2〜5分、低リスクで15〜30分
  • 絶対期限: 操作の有無に関係なく切れる上限。事務作業向けなら4〜8時間が目安

どちらもサーバー側で強制する必要があります。クライアントのトークンに経過時間を持たせて判断する作りは、改ざんで延長できるからです。さらにログアウトの応答にはClear-Site-DataやCache-Control: no-storeを付けて、ブラウザーに残る情報も消す方法があります。ヘッダーの確認手順はCache-Controlをcurl -Iで点検する記事にあります。

CSRF対策の有無を見る

CSRFは、ログイン中のユーザーのブラウザーに、意図しない操作を送らせる攻撃です。ブラウザーがCookieを自動で付けるため、Cookie認証のサイトでは成立します。OWASPが示す対策の優先順は次のとおりです。

  1. 組み込みのCSRF保護があれば、まずそれを使う
  2. ステートフルならsynchronizer tokenパターン、ステートレスなら署名つきdouble-submit cookie
  3. フォームを使えないAPIでは、カスタムリクエストヘッダー
  4. Origin・Refererの検証、Fetch Metadataヘッダー(Sec-Fetch-Site)を補助に使う

SameSiteは補助の位置づけです。OWASPは、SameSiteをトークンの代わりにせず、多層防御の一部として扱うよう書いています。Laxでは、GETなどの安全なメソッドによるトップレベルのナビゲーションでCookieが送られます。そのため、GETで状態を変えるエンドポイントがあると、SameSite=Laxでは止まりません。OWASPはこれを、SameSiteによる防御が実際に破れる最も多い型としています。

また、SameSiteは「オリジン」でなく「登録可能なドメイン」単位で判定されます。app.example.comのCookieは、同じ親ドメインのどのサブドメインからの要求も同一サイト扱いです。管理下にないサブドメインがあるなら、トークンなしでSameSiteだけに頼れません。

点検では、次の3点をClaude Codeに洗い出させます。

  • 状態を変える処理(登録・更新・削除・送金など)にGETで到達できる経路
  • Cookie認証のルートに、CSRFトークンの検証ミドルウェアが掛かっているか
  • 例外として検証を外しているルート(@csrf_exemptのような指定)があるか、その理由

Claude Codeへの頼み方と権限

点検は読み取りだけで済みます。コードを書き換える前に、まず報告だけを受け取る形にします。権限の仕組みとして、Claude Codeは手動モードでは読み取り専用から始まり、編集やコマンド実行の前に確認を求めます。ls・cat・grep・findといった読み取り系のコマンドは、確認なしで走ります。点検に使うのはこの範囲のコマンドです。

秘密情報の読み出しを避けるため、.claude/settings.jsonにReadの拒否ルールを置きます。

{
  "permissions": {
    "deny": [
      "Read(./.env)",
      "Read(./secrets/**)"
    ]
  }
}

拒否ルールは許可ルールより先に評価されます。現在の設定は/permissionsで見直せます。

CLAUDE.mdに、点検の観点を短く書いておくと、毎回の指示が減ります。

## セッションとCSRFの点検
- 報告のみ。ファイルは編集しない
- 各指摘は「ファイル:行」「該当する設定または呼び出し」で示す
- Cookieの属性は、明示した値と、フレームワークの既定に任せた値を分けて書く
- 判断できない項目は「コードからは不明」と書き、推測で埋めない

依頼の文面は、次のように範囲と出力形式を決めます。

このリポジトリのセッションCookieとCSRF対策を点検してください。ファイルは編集しません。
1. セッションCookieの設定箇所を探し、Secure・HttpOnly・SameSite・Domain・Path・接頭辞を表にする
2. ログイン成功時の処理で、セッションIDを再発行しているかを確認する
3. ログアウト処理で、サーバー側のセッション破棄が呼ばれているかを確認する
4. POST/PUT/PATCH/DELETEのルートに、CSRF検証が掛かっているかを一覧にする
5. GETで状態を変えているルートがないか確認する
結果は「問題あり」「問題なし」「コードからは不明」に分け、根拠となるファイルと行を付けてください。

「コードからは不明」を設けるのは、リバースプロキシやフレームワーク側の既定で決まる値を、推測で「問題なし」にさせないためです。

結果をどう読み、どう直すか

Claude Codeの報告は、そのまま真実として扱わず、一覧の根拠行を自分で開いて確かめます。報告の読みどころは3つです。

  • 属性が「既定任せ」と書かれた項目は、実際の応答ヘッダーで確かめる(本番とローカルで設定が違うことがある)
  • 再発行の呼び出しが見つからない場合、認証ライブラリ側が内部で行っていないかを調べる
  • CSRFの免除ルートは、Webhookのように署名で別に守られているかを見る

修正は、報告を受けた後に別の依頼として出します。修正のレビュー方法は、セキュリティ修正PRのレビュー手順で扱っています。CIで定期的に脆弱性を検査したいなら、GitHub Actionsの脆弱性をzizmorで点検する記事も参考になります。

よくあるつまずき

HttpOnlyを付ければCSRFも防げる、という誤解があります。HttpOnlyはJavaScriptからの読み出しを止める属性で、ブラウザーがCookieを自動送信する点は変わりません。CSRFには別の対策が要ります。

SameSite=Laxが既定だから安全、という判断も危うい点です。Djangoのセッションの既定はLaxですが、GETで状態を変えるビューがあれば成立し得ます。OWASPが「GETの全ハンドラーを点検する」ことを条件にしているのはそのためです。

最後に、SameSiteの属性を明示せずブラウザーの既定に任せると、古いブラウザーや埋め込みブラウザーでは属性なしと同じ挙動になり得ます。OWASPはブラウザーの既定値に頼らないよう明記しています。

まとめ

点検は「属性の表」「再発行の有無」「破棄の呼び出し」「CSRF検証の網羅」の4枚の一覧に落ちます。Claude Codeは読み取り専用でこの一覧を作るのに向いていますが、本番の応答ヘッダーとの突き合わせは人の手で行う必要があります。コードに現れない設定が、最後の穴になりやすいためです。

参照した一次ソース

この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。

  1. code.claude.com/docs/en/security
  2. code.claude.com/docs/en/permissions
  3. cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html
  4. cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sh…
  5. docs.djangoproject.com/en/5.2/ref/settings
  6. expressjs.com/en/resources/middleware/session.html
この記事を共有:XはてブLinkedIn