← レッドチーム / 攻撃技術
RED TEAM  ·  ■ XSS   ■ CSRF

名前は似てるが、
XSSCSRF
正反対の攻撃。

どちらも「Webの信頼」を悪用しますが、悪用する信頼の向きが逆です。XSS はサイトがユーザーを信頼しすぎること、CSRF はサイトがブラウザを信頼しすぎることを突きます。ここが腹落ちすれば、対策が別物になる理由も見えます。

XSS Cross-Site Scripting

他人のブラウザで、悪意あるスクリプトを実行させる。サイトが受け取った入力を、無害化せずページに埋め込んでしまうのが原因。

CSRF Cross-Site Request Forgery

ログイン済みユーザーに、意図しない操作を送信させる。ブラウザが Cookie を自動送信する仕組みに便乗する。

1 核心の違い

「誰を信頼しすぎたか」で分かれる

2つの攻撃は、Webアプリが暗黙に置いている「信頼」の別々の穴を突きます。まず絵で捉えます。

XSS ── サイトが「ユーザー入力」を信頼しすぎる
攻撃者スクリプトを投稿
無害化せず保存/反射──▶
サイトそのまま出力
スクリプト入りHTML──▶
被害者ブラウザで実行
被害者のブラウザは、サイトから来たスクリプトだから安全と信じて実行してしまう。悪いのは「入力を信じたサイト」。
CSRF ── サイトが「ブラウザからのリクエスト」を信頼しすぎる
被害者ログイン済み
罠サイトを開く──▶
罠サイト裏でリクエスト
Cookie 自動添付で送信──▶
サイト本人と誤認
サイトは Cookie が付いている=本人の操作と信じて処理してしまう。悪いのは「リクエストの出所を確かめなかったサイト」。
一言でいうと

XSS はコードを盗ませる(実行させる)攻撃、CSRF は操作をさせる攻撃。XSS で奪ったスクリプト実行権を使って CSRF 対策トークンごと盗む、という合わせ技もあり、XSS があると CSRF 対策は無力化されがちです。だから優先度は XSS の根絶が上。

2 XSS の仕組み

なぜ起こるか:入力がコードとして解釈される

XSS の根っこは1つです。ユーザーが入力した文字列を、HTML/JavaScript として解釈される場所へ、無害化せずに出力してしまうこと。ブラウザは「データ」と「コード」を見た目で区別できないので、<script> と書かれていればコードとして実行します。

たとえば掲示板が、名前欄の入力をそのまま表示するとします。

// サーバーが受け取った名前をそのまま埋め込む(危険)
echo "<p>こんにちは、" . $_GET['name'] . "さん</p>";

ここに name=<script>alert(document.cookie)</script> を渡すと、出力はこうなります。

<p>こんにちは、<script>alert(document.cookie)</script>さん</p>

ブラウザはこの <script> を「表示する文字」ではなく「実行するコード」と解釈します。これで攻撃者の JavaScript が被害者のブラウザの、そのサイトの権限で動きます。Cookie(セッション)の窃取、なりすまし、フォーム改ざん、キーロガー設置まで何でもできます。

3つのタイプ

「スクリプトがどこを経由して届くか」で分類されます。

Stored / 格納型

投稿内容などとしてサーバーに保存され、そのページを開いた全員に配信される。掲示板・プロフィール・コメント欄が典型。被害が広く、最も危険。

Reflected / 反射型

URL のパラメータなどに仕込まれ、サーバーがその場で応答に echo(反射)する。攻撃用 URL を踏ませることで成立するので、フィッシングと組み合わせて使われる。

DOM-based / DOM型

サーバーを経由せず、ブラウザ内の JavaScriptlocation.hash などの値を innerHTML に書き込むことで発火する。サーバーのログに残りにくく、フロント側の実装が原因。

3 XSS の対策

「出力する瞬間」に無害化するのが本丸

出力エスケープ(最重要)

データを HTML に出す瞬間に <&lt;>&gt;"&quot; へ変換する。こうすれば <script> は「実行されるタグ」ではなく「画面に出る文字列」になる。出力先(HTML本文/属性値/JavaScript内/URL)ごとに正しいエスケープが違う点に注意。

フレームワークの自動エスケープを使う

React(JSX の {})、Vue の {{ }}、各テンプレートエンジンはデフォルトでエスケープする。dangerouslySetInnerHTMLv-html のような自動エスケープを外す機能を安易に使わない

Content-Security-Policy (CSP)

「どこから来たスクリプトを実行してよいか」をブラウザに宣言するヘッダ。インラインスクリプトを禁止すれば、埋め込まれた <script> が実行されない。エスケープ漏れの保険になる多層防御。

HttpOnly Cookie

セッション Cookie に HttpOnly 属性を付けると、JavaScript の document.cookie から読めなくなる。XSS が起きてもセッション窃取だけは防げる被害軽減策。

入力バリデーション(補助)

想定外の文字を入口で弾く。ただし入力対策だけに頼らない——本丸はあくまで出力時のエスケープ。入力チェックはすり抜ける経路が多い。

4 CSRF の仕組み

なぜ起こるか:ブラウザが Cookie を勝手に付ける

CSRF の根っこは、ブラウザの親切な仕様です。あるサイト宛のリクエストには、そのサイトの Cookie が自動で添付される——たとえそのリクエストが、別の(罠)サイトのページから発生していても。

あなたが銀行サイトにログイン中(=セッション Cookie を保持)だとします。別タブで開いた罠サイトに、こんな仕込みがあったら——

<!-- 罠サイトのHTML。画像に見せかけて送金リクエストを発射 -->
<img src="https://bank.example/transfer?to=attacker&amount=100000">

ブラウザはこの src を読みにいくとき、bank.example の Cookie を自動で付けて送信します。銀行サーバーから見れば「正しいセッション Cookie 付きのリクエスト」なので、本人の送金指示と区別できません。被害者は画像が表示されないな、と思うだけで、裏で送金が実行されます。

ポイント

攻撃者は Cookie の中身を盗む必要がない。ブラウザに「代わりに送らせる」だけ。だから CSRF は「リクエストが本当に本人の意思か」を確かめれば防げる。

5 CSRF の対策

「このリクエストは本当に本人の画面から来たか」を検証する

CSRF トークン(王道)

フォーム表示時に、推測不能なランダム値をページに埋め込み、送信時に照合する。罠サイトはこのトークンを知り得ないので偽リクエストを作れない。Synchronizer Token Pattern。多くのフレームワークに標準搭載。

SameSite Cookie 属性

Cookie に SameSite=Lax(or Strict)を付けると、別サイト起点のリクエストには Cookie が付かなくなる。CSRF の前提そのものを崩す強力な一手。現代ブラウザは Lax がデフォルト寄り。

Origin / Referer 検証

サーバー側で、リクエストの OriginReferer ヘッダが自サイトかを確認する。別サイト起点なら拒否。トークンと併用する多層防御として有効。

重要操作に再認証・確認を挟む

送金・パスワード変更など影響の大きい操作では、パスワード再入力や確認ステップを要求する。自動発射の一撃では通らなくなる。

なお <img> や単純フォームで発射できるのは「単純リクエスト」。Content-Type: application/json を要求する API などは、そもそもプリフライト(CORS)が挟まって罠サイトから叩きにくい。ただしこれは副次的効果で、CSRF 対策そのものではない点に注意。

6 早見表

横に並べて確認

観点XSSCSRF
正式名 Cross-Site Scripting Cross-Site Request Forgery
何をされる ブラウザで悪意のスクリプトを実行される 本人の権限で意図しない操作を送信される
悪用する信頼 サイト → ユーザー入力 サイト → ブラウザ(Cookie)
攻撃者が奪うもの スクリプト実行権(Cookie・DOM 何でも) 操作の実行(Cookie 中身は見えない)
主因 出力時の無害化漏れ リクエスト出所の未検証
主対策 出力エスケープ・CSP・HttpOnly CSRFトークン・SameSite・Origin検証
覚え方

XSS = サイトが悪いスクリプトを「配ってしまう」/ CSRF = 本人に操作を「させてしまう」。XSS はデータをコードにさせない(エスケープ)、CSRF はリクエストの本人性を確かめる(トークン)。守る層が違う。