XSSとCSRFの違いとは?仕組み・被害・対策を実装レベルで徹底比較
XSS(クロスサイトスクリプティング)とCSRF(クロスサイトリクエストフォージェリ)は、名前も攻撃の入口も似ているため混同されやすい脆弱性です。しかし決定的な違いは「どこで悪意ある処理が動くか」にあります。XSSは利用者のブラウザ上で攻撃者のスクリプトを実行させる攻撃、CSRFはログイン済み利用者のセッションを流用してサーバへ不正なリクエストを送りつける攻撃です。この記事では両者を攻撃対象・仕組み・被害・対策の4軸で比較し、出力エスケープ・CSP・CSRFトークン・SameSite Cookieといった実装レベルの防御策と、両者が絡み合う複合リスクまで整理します。
まとめ
- XSS=利用者のブラウザで攻撃者のスクリプトを実行させる(クライアント側で発火)。
- CSRF=被害者のログイン済みセッションを使い、サーバへ正規を装った不正リクエストを送る(サーバ側で発火)。
- 見分けの軸は「処理が動く場所」「盗まれる/悪用されるもの」「被害者がログイン中である必要の有無」。
- 対策の核は、XSSが出力エスケープ+CSP+HttpOnly Cookie、CSRFがCSRFトークン+SameSite Cookie。
- 両者は無関係ではない。XSSを残すとCSRFトークンごと盗まれ、CSRF対策が破られる。塞ぐ優先順位はXSSが先。
以下、それぞれの仕組みを押さえたうえで、比較表と実装コードで違いと対策を具体化します。
XSS(クロスサイトスクリプティング)の仕組みと種類
XSSは、Webアプリが利用者の入力を検証・エスケープせずにページへ出力してしまう欠陥を突く攻撃です。攻撃者は入力欄やURLパラメータに<script>alert(document.cookie)</script>のようなスクリプトを紛れ込ませ、別の利用者のブラウザ上でそれを実行させます。実行されるのは被害者の権限下のJavaScriptなので、Cookieやセッション情報の窃取、画面の改ざん、フィッシング誘導まで可能になります。XSSは注入されたスクリプトがどこを経由するかで、次の3種類に分かれます。
反射型XSS(リクエストに含めた値が即時反射)
検索結果やエラー画面など、リクエストのパラメータをそのままページに埋め込む箇所で発生します。攻撃者は不正なスクリプトを仕込んだURLを被害者に踏ませ、その場でスクリプトを反射・実行させます。攻撃用URLをメールやSNSで配布する手口が典型です。
格納型(蓄積型)XSS(サーバ保存後に全閲覧者へ発火)
掲示板やレビュー、プロフィール欄など、投稿内容がデータベースに保存されて再表示される箇所で発生します。一度仕込めばページを開いた全利用者に対して発火するため、反射型より影響範囲が広く危険度が高い類型です。
DOM型XSS(クライアントJSが動的に生成する箇所)
サーバを経由せず、ブラウザ上のJavaScriptがlocation.hashなどの値をそのままDOMへ書き込むことで発生します。サーバ側のレスポンスには痕跡が残りにくく、サーバ側のエスケープだけでは防げない点が対策を難しくします。
CSRF(クロスサイトリクエストフォージェリ)の仕組みと攻撃の流れ
CSRFは、利用者があるサイトにログインした状態のまま、攻撃者が用意した別サイトを開いた瞬間を突く攻撃です。ブラウザはリクエスト時にそのサイトのCookieを自動送信するため、攻撃者は被害者のセッションを借りて「本人が操作したかのような」リクエストをサーバへ送れます。攻撃の流れは次のとおりです。
- 被害者が対象サイト(例:会員サイト)にログインし、セッションCookieを保持している。
- 被害者が攻撃者のページを開く。そこには対象サイトへ自動送信するフォームや画像タグが仕込まれている。
- ブラウザがCookieごとリクエストをPOSTし、サーバは正規利用者の操作として処理する(退会・送金・設定変更など)。
XSSと違い、攻撃者は被害者のブラウザから情報を盗み出すわけではありません。あくまでサーバ側で「本人になりすました正規処理」を実行させる点がCSRFの本質です。そのため被害者が対象サイトにログイン中であることが攻撃成立の前提になります。
XSSとCSRFの違い(攻撃対象・仕組み・被害の比較)
両者の違いを実務で使う観点に絞って表に整理します。混同を避ける最短の判断軸は「悪意あるコードが利用者のブラウザで動くならXSS、サーバが正規処理として受け取るならCSRF」です。
| 観点 | XSS | CSRF |
|---|---|---|
| 処理が動く場所 | 利用者のブラウザ | サーバ(正規処理として) |
| 攻撃対象 | 利用者・ブラウザ | ログイン中のセッション |
| 仕組み | 不正スクリプトの注入・実行 | 正規リクエストの偽装 |
| 前提条件 | なし | 被害者がログイン中 |
| 主な被害 | Cookie窃取・画面改ざん | 意図しない操作の実行 |
| 主な対策 | 出力エスケープ・CSP | CSRFトークン・SameSite |
被害の性質も対照的です。XSSは「利用者から情報を盗む・利用者を操る」攻撃であるのに対し、CSRFは「利用者の権限でサーバを操作する」攻撃です。同じWebアプリの脆弱性でも、守るべき対象と防御の置き場所が異なります。データベースを直接狙うSQLインジェクションとも合わせて、注入系・偽装系の攻撃面を切り分けて理解しておくと対策の優先度を判断しやすくなります。
XSSの対策(出力エスケープとCSPの実装)
XSS対策の基本は、利用者由来のデータを「出力する文脈に合わせてエスケープする」ことです。HTML本文、属性値、JavaScript内、URLでは無害化のルールが異なるため、出力箇所ごとに適切なエスケープ関数を通します。HTMLコンテキストではPHPなら次のように記述します。
// 出力時に必ずエスケープ(HTMLコンテキスト)
echo htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
入力時のバリデーションだけに頼らないのが要点です。入力を許可する文字種を絞ることは有効ですが、最終防衛線は必ず出力時のエスケープに置きます。加えて、Content-Security-Policy(CSP)をレスポンスヘッダに設定し、実行を許可するスクリプトの取得元を制限すると、万一注入されても外部スクリプトの実行やインラインスクリプトの発火を抑えられます。
Content-Security-Policy: default-src 'self'; script-src 'self'
さらにセッションCookieにHttpOnly属性を付けると、JavaScriptからCookieを読み取れなくなり、XSSでCookieを盗まれる被害を軽減できます。エスケープを主対策、CSPとHttpOnlyを多層防御と位置づけるのが実務的な構成です。ブラウザストレージ(Cookie・localStorage)の特徴を踏まえ、機密性の高い値をJSから触れる場所へ置かない設計も併せて検討します。
CSRFの対策(トークンとSameSite Cookieの実装)
CSRF対策の中心は、リクエストが「そのサイトの正規画面から送られたか」を検証することです。最も確実なのはCSRFトークンで、フォーム表示時にサーバがランダムなトークンを発行して隠しフィールドに埋め込み、送信時に照合します。
<input type="hidden" name="csrf_token" value="9f3a...b2">
攻撃者は被害者のセッション用トークンを知り得ないため、値が一致しないリクエストを弾けます。これに併せてCookieのSameSite属性を設定すると、クロスサイトからのCookie送信自体を制限できます。Chrome 80以降は未指定時のデフォルトがLaxに変更され、Firefox 96も追随しています。
| SameSite値 | クロスサイト送信 | CSRFへの効果 | 主な用途 |
|---|---|---|---|
| Strict | 一切送らない | 最も強い | 管理画面・決済 |
| Lax | トップレベルGETのみ | POST等を遮断 | 一般的な既定 |
| None | 常に送る(Secure必須) | なし | クロスサイト連携 |
Set-Cookie: session=abc123; SameSite=Lax; Secure; HttpOnly
補助的にリクエストのOriginヘッダ(無ければRefererヘッダ)を検証し、想定外のドメインからの送信を拒否する手法も有効です。フレームワークを使う場合は自前実装より標準機能を優先します。たとえばSpring SecurityによるCSRF対策ではトークン検証機構が標準で組み込まれており、自前実装より標準機能を有効化するのが安全です。
XSSとCSRFの複合リスクと対策の優先順位
XSSとCSRFは別々の脆弱性ですが、実際の防御では切り離せません。XSS脆弱性が残っていると、注入されたスクリプトがページ内のCSRFトークンを読み取ってリクエストに含められるため、CSRFトークンによる防御はその場で無力化されます。HttpOnlyでCookieを守っても、DOM上に描画されたトークンはJavaScriptから見えるからです。したがって「CSRFトークンを入れたから安全」ではなく、まずXSSを塞ぐことが前提条件になります。優先順位はXSSが先、CSRFが後です。
SameSite Cookieについても過信は禁物です。SameSite=LaxはトップレベルのGETナビゲーションではCookieを送るため、状態変更をGETで実装している設計では守れません。また外部サービス連携でSameSite=Noneを設定しているCookieは、その時点でCSRFの保険が外れます。「SameSiteを設定したからCSRFトークンは不要」という判断は、これらの抜け道を見落とす典型的な失敗パターンです。状態を変更する操作は必ずPOST等に限定し、CSRFトークンとSameSiteを併用する二重化を推奨します。逆に、参照だけで副作用のないGET専用の公開ページにCSRFトークンを付けるのは過剰で、保守コストに見合いません。守るべきは「副作用のある操作」だと割り切ることが実装判断の軸になります。
よくある質問
XSSとCSRFはどちらが危険ですか?
単純な優劣はつけられませんが、対処の優先順位ではXSSを先に塞ぐべきです。XSSは利用者のブラウザで任意のスクリプトを実行できるため、Cookie窃取からCSRFトークンの読み取りまで波及し、CSRF対策そのものを無効化してしまうからです。影響範囲の広さでは、保存されたスクリプトが全閲覧者に発火する格納型XSSが特に危険です。まずXSSを封じ、そのうえでCSRF対策を重ねる順序が実務的です。
CSRFトークンとSameSite Cookieはどちらを使うべきですか?
どちらか一方ではなく併用が推奨されます。CSRFトークンはリクエストの正当性を明示的に検証する主対策、SameSite CookieはクロスサイトからのCookie送信を制限する多層防御です。SameSite=Laxは既定として有効ですが、GETでの状態変更やSameSite=Noneの連携Cookieでは守れません。トークンで確実に検証し、SameSiteで送信経路を絞る二重化が、抜け道を減らす現実的な構成です。
CSPを設定すればXSSは完全に防げますか?
CSPだけでXSSを完全に防ぐことはできません。CSPは実行を許可するスクリプトの取得元を制限し、被害を軽減する多層防御の一つです。しかし設定が緩い(unsafe-inlineの許可など)と効果が薄れ、DOM型XSSのように既存の許可スクリプト内で発火する攻撃には限界があります。あくまで出力エスケープを主対策とし、CSPは補強と位置づけてください。
反射型XSSと格納型XSSの違いは何ですか?
不正スクリプトがどこを経由するかが違います。反射型は、リクエストに含めた値がその場でページに反射・実行される類型で、攻撃者は不正URLを被害者に踏ませます。格納型(蓄積型)は、投稿内容などがサーバに保存され、以降その画面を開いた全利用者に対して発火する類型です。格納型は一度の仕込みで影響が広がるため、反射型より危険度が高いと評価されます。
CSRF対策にRefererチェックだけで十分ですか?
Referer(またはOrigin)チェックは補助策であり、それ単独では不十分です。プライバシー設定やプロキシによってRefererが送信されない環境があり、送られてこない場合の扱いを誤ると正規利用者を弾いたり、逆に検証を素通しさせたりします。CSRFトークンによる検証を主対策に据え、Origin/Refererチェックとメインで併用する構成にしてください。