はじめに
Webアプリケーションの認証管理において、Cookie(クッキー)は非常に便利な仕組みです。セッションIDをCookieに保存しておくことで、ブラウザはリクエストのたびに自動的に認証情報をサーバーへ送信してくれます。
しかし、この「自動送信される」という性質を悪用するのが、CSRF(クロスサイトリクエストフォージェリ:Cross-Site Request Forgery) というサイバー攻撃です。
近年、ブラウザ側でのCookieのデフォルトの挙動変更(SameSite属性の適用など)によって対策は進んでいますが、現在でも開発者が適切な知識を持っていなければ、深刻なCSRF脆弱性を埋め込んでしまうリスクがあります。本記事では、CSRFの防御手段であるSameSite属性の基本と、トークンを用いた防衛設計について解説します。
1. CSRF攻撃のメカニズム
CSRFは、攻撃者が用意した罠サイトにログイン済みのユーザーを誘導し、「ユーザーのブラウザ」を経由して、対象のWebアプリケーション(例: 銀行やECサイト)に対して意図しない操作(送金、パスワード変更など)を実行させる攻撃です。
- ユーザーが銀行サイト(
bank.com)にログインし、セッションCookieがブラウザに保存される。 - ユーザーが攻撃者の罠サイト(
evil.com)にアクセスする。 - 罠サイト内のスクリプトが、
bank.comの送金API(POST /transfer)に対してリクエストを送信する。 - ブラウザは、
bank.com宛てのリクエストであるため、自動的にセッションCookieを添付して送信してしまう。 - 銀行サーバーは正規のセッションとして処理し、送金が実行される。
2. 防御策1: Cookieの SameSite 属性
CSRFの最も手軽かつ強力な対策が、Cookieの SameSite 属性 を設定することです。これは、「他サイト(クロスサイト)から開始されたリクエストに、このCookieを添付して送信するかどうか」をブラウザに指示する属性です。
3つの設定値
Set-Cookie: sessionId=abc123; Secure; HttpOnly; SameSite=Lax
| 設定値 | 説明(挙動) |
|---|---|
| SameSite=Strict | クロスサイトのリクエストには一切Cookieを送信しない。別サイトに貼られた直リンクから遷移した場合でも送信されないため、最も安全だが利便性が下がる(ログイン状態が引き継がれない)。 |
| SameSite=Lax | 原則としてクロスサイトでは送信しないが、「ユーザーがリンクをクリックした際(トップレベルナビゲーションのGETリクエスト)」のみ送信を許可する。通常のWebアプリにおけるデファクトスタンダード。 |
| SameSite=None | すべてのクロスサイトリクエストでCookieを送信する。利用の際は Secure 属性(HTTPS通信限定)が必須。サードパーティCookieなどに利用される。 |
注意点: SameSite=Lax の限界
現在、ほとんどのモダンブラウザは SameSite 属性のデフォルト値を Lax として扱います。これにより多くの単純なCSRF(罠サイトからPOSTリクエストを送るなど)は防げます。
しかし、以下のようなケースでは Lax だけでは不十分です。
- GETメソッドでデータ更新処理を行っている:
GET /delete?id=1のような設計をしている場合、Laxでは直リンクをクリックした際にCookieが送信されるため、CSRFが成立してしまいます。(そもそもデータ更新にGETを使うべきではない理由がここにあります) - 古いブラウザの対応:
一部の古いブラウザやレガシーなWebView環境では、
SameSite属性に対応していない場合があります。
3. 防御策2: ダブルサブミットクッキー(Double Submit Cookie)パターン
インフラ側の挙動に依存せず、より強固にCSRFを防ぐために広く使われている手法が 「CSRFトークン」 の検証です。特にステートレスなSPAなどでよく使われるのが「ダブルサブミットクッキー」パターンです。
仕組み
- サーバーは、暗号化されたランダムなトークン(CSRFトークン)を生成し、Cookieとしてクライアントに送る。
- クライアント(JavaScript)は、Cookieの値を読み取る(またはAPI経由で取得する)とともに、HTTPリクエストのカスタムヘッダー(
X-CSRF-Token)にそのトークンを設定してAPIを叩く。 - サーバーは、「Cookie内のトークン」と「カスタムヘッダー内のトークン」が一致しているかを検証する。
なぜ安全なのか?
攻撃者のサイト(evil.com)からリクエストを送る際、ブラウザはCookieを自動送信することはできても、「他ドメインのCookieをJavaScript(document.cookie)で読み取ってカスタムヘッダーにセットする」ことは、ブラウザの同一起源ポリシー(SOP: Same-Origin Policy)によって絶対に禁止されているためです。
まとめ
CSRF攻撃を防ぐためには、ブラウザの仕様変化(SameSite)に甘んじることなく、適切なプロトコル設計を行う必要があります。
- すべてのCookieに
SameSite=LaxまたはStrictを明示する - データ変更を行うAPIには
GETメソッドを使用せず、必ずPOST,PUT,DELETEを使用する - SPAなどではカスタムHTTPヘッダーを用いたCSRFトークンの二重検証(Double Submit)を導入する
これらを徹底し、セッション情報の漏洩やなりすまし操作のリスクを完全にシャットアウトしましょう。
