情報処理安全確保支援士試験において、Webセキュリティ分野は避けて通れない最重要テーマです。その中でも「クロスサイトスクリプティング(XSS)」は、SQLインジェクションと並んで頻出の脆弱性であり、実務でも多くの事故原因となっています。
「単にポップアップが出るだけでしょ?」と侮ってはいけません。XSSは、セッションハイジャックによるアカウント乗っ取りや、個人情報の大量漏洩、さらにはフィッシング詐欺の踏み台にされるなど、企業の信頼を失墜させる深刻な被害を引き起こします。
この記事では、XSSが発生する根本的な仕組みから、試験で問われる「3つの種類」、そしてなぜ「特定の文字を削除する」という対策では防げないのかといった実務的なポイントまで、図解を交えて徹底解説します。
クロスサイトスクリプティング(XSS)の仕組みと脅威
クロスサイトスクリプティング(XSS)とは、Webアプリケーションの脆弱性を利用し、攻撃者が作成した「悪意のあるスクリプト」を、閲覧者のWebブラウザ上で実行させる攻撃手法です。
本来、Webブラウザには「同一生成元ポリシー(Same-Origin Policy)」というルールがあり、異なるサイト間の干渉は制限されています。しかし、XSSはこの制限を回避(クロス)し、信頼されているサイト上で不正なスクリプトを動かすため、この名前がついています。
なぜXSSが発生するのか?
Webサイトは、ユーザーからの入力を受け取り、それを処理して画面に表示します。検索キーワードや掲示板の書き込みなど、ユーザーが入力したデータがそのままHTMLとして出力されるケースが典型的です。
このとき、アプリケーションが入力値を適切に処理せず、そのままHTMLとして出力してしまうと、ブラウザはそれが「ユーザーの入力した文字」なのか「Webページの構成要素(タグやスクリプト)」なのかを区別できません。その結果、攻撃者が入力した <script> タグなどが、ブラウザによってプログラムとして実行されてしまうのです。
たとえば、検索機能で「あなたが検索したキーワードは○○です」と表示する画面があったとします。ここで検索欄に <script>alert('攻撃')</script> と入力され、それがそのままHTMLに埋め込まれると、ブラウザはこれを実行可能なJavaScriptコードとして認識し、アラートが表示されてしまいます。これがXSSの基本的なメカニズムです。

XSSによる具体的な被害
スクリプトが実行されると、攻撃者はユーザーのブラウザ上で以下のことが可能になります。
- セッションハイジャック(なりすまし):
document.cookieを参照してセッションIDを盗み出し、正規ユーザーになりすまして不正ログインや送金を行う - Webページの改ざん: 画面上の情報を書き換え、偽のニュースを表示したり、フィッシングサイトへのリンクを表示したりする
- 情報の漏洩: 画面に表示されている個人情報や、非公開データを読み取って外部へ送信する
- マルウェア感染: 閲覧者を攻撃者の用意した悪意あるサイトへ強制的にリダイレクト(転送)させる
特に危険なのがセッションハイジャックです。多くのWebサービスでは、ログイン状態を維持するためにセッションIDをCookieに保存しています。このCookieが盗まれると、攻撃者はパスワードを知らなくてもそのユーザーとして振る舞うことができるのです。
さらに、近年ではXSSを起点としたより複雑な攻撃も増えています。たとえば、管理者アカウントを乗っ取った後、そのアカウントの権限を悪用して、データベース全体にアクセスしたり、システム設定を変更したりするケースです。このように、XSSは単独でも危険ですが、他の攻撃の入口としても利用されることを理解しておく必要があります。
試験で問われる「3つのXSS」を完全理解
情報処理安全確保支援士試験では、XSSをその発生メカニズムによって3つのタイプに分類して出題します。「反射型」「蓄積型」「DOM Based」の違いを明確に理解しましょう。

1. 反射型XSS(Reflected XSS)
攻撃者が用意した「罠のURL」をユーザーがクリックすることで発動するタイプです。リクエストに含まれたスクリプトが、サーバーでの処理を経て、そのままレスポンス(HTML)として「反射」されることで実行されます。
- 発生箇所: 検索結果の表示、エラーメッセージ、入力確認画面など
- 特徴: スクリプトはサーバーに保存されません。攻撃者はメールやSNSで罠URLをターゲットに踏ませる必要があります
具体的な攻撃の流れを見てみましょう。攻撃者は、まず脆弱性のあるWebサイトのURLにスクリプトを埋め込みます。たとえば https://example.com/search?q=<script>悪意のあるコード</script> のようなURLです。このURLをメールやSNSで拡散し、ユーザーにクリックさせます。
ユーザーがこのURLをクリックすると、サーバーはURLに含まれる検索キーワード(この場合はスクリプト)をそのまま検索結果ページに埋め込んで返します。ブラウザはこれを受け取り、HTMLとして解釈してスクリプトを実行してしまいます。
反射型XSSの被害を防ぐには、ユーザー教育も重要です。不審なURLをクリックしない、信頼できないメールのリンクは開かないといった基本的な対策も、組織全体のセキュリティレベルを高めることにつながります。
2. 蓄積型XSS(Stored XSS / Persistent XSS)
攻撃者が投稿したスクリプトが、サーバー側のデータベースなどに「保存(蓄積)」され、そのページを閲覧したユーザー全員に対して攻撃が実行されるタイプです。一度攻撃が成功すると、その書き込みが削除されるまで被害が継続するため、非常に危険度が高いです。
- 発生箇所: 掲示板、レビューサイト、SNSのタイムライン、ブログのコメント欄など
- 特徴: 罠URLを踏ませる必要がなく、正規のページを見るだけで被害に遭います。被害が広範囲に及びやすいのが特徴です
蓄積型XSSは、反射型と比べて攻撃者にとって非常に効率的です。一度スクリプトを投稿してしまえば、そのページを訪れる全てのユーザーが自動的に攻撃対象となるからです。
実際の事例として、ある大手SNSサイトで蓄積型XSSが発見された際には、攻撃者が投稿したプロフィール情報を閲覧した数千人のユーザーのセッションIDが盗まれました。この攻撃は、管理者が気づいて該当の投稿を削除するまでの数時間で多数の被害を生みました。
蓄積型XSSの特に厄介な点は、正規のユーザーが普通にサイトを使っているだけで被害に遭う点です。ユーザー側では防ぎようがないため、サイト運営者側での徹底した対策が不可欠です。
3. DOM Based XSS
これまでの2つがサーバー側の処理に問題があったのに対し、これはクライアント側(ブラウザ上)のJavaScriptの処理に問題があるタイプです。サーバーから送られてくるHTMLにはスクリプトが含まれていなくても、ブラウザ上のJavaScriptがURLの一部(フラグメント識別子など)を読み取り、それを動的に画面(DOM)に書き出す際にスクリプトが実行されます。
- 発生箇所: JavaScriptで動的にコンテンツを生成しているページ(SPAなど)
- 特徴: サーバーのアクセスログに攻撃の痕跡が残らない場合があります(URLの
#以降はサーバーに送信されないため)。サーバー側のWAFでは検知できないこともあります
DOM Based XSSの典型的な例を見てみましょう。あるWebページに次のようなJavaScriptコードがあったとします。
var keyword = location.hash.substring(1);
document.getElementById('result').innerHTML = keyword;
このコードは、URLの # 以降の文字列を取得し、それを innerHTML を使ってページに表示しています。ここで攻撃者が https://example.com/#<script>alert('XSS')</script> というURLを作成すると、ブラウザ上でこのスクリプトが実行されてしまいます。
重要なのは、この攻撃ではサーバーに悪意のあるデータが送信されていない点です。すべての処理がブラウザ内で完結するため、サーバー側のログには攻撃の痕跡が残りません。これが、DOM Based XSSの検出と対策を難しくしている要因です。
近年、シングルページアプリケーション(SPA)の普及により、DOM Based XSSのリスクは増大しています。ReactやVue.js、Angularといったモダンなフレームワークを使用する際も、開発者が不適切にDOMを操作すると、この脆弱性が生まれる可能性があります。
確実に防ぐ!XSS対策の鉄則と「やってはいけない」対策
XSSは非常に危険ですが、正しい対策を行えば防ぐことができます。ここで重要なのは、「効果のない対策」を行わないことです。
1. 【根本的対策】サニタイジング(エスケープ処理)
XSS対策の要(かなめ)は、出力時にHTMLの特殊文字を無害化することです。これをエスケープ処理、またはサニタイジングと呼びます。Webブラウザにとって特別な意味を持つ文字を、ただの「文字」として扱うように変換します。
<→<>→>&→&"→"'→'
これにより、攻撃者が <script> と入力しても、ブラウザには <script> という文字列として渡されるため、スクリプトとして実行されることなく、画面には文字として表示されます。
エスケープ処理の重要なポイントは、入力時ではなく出力時に行うことです。データベースには元の入力値をそのまま保存し、HTMLとして出力する直前にエスケープを行います。これにより、同じデータを異なる形式(HTML、JSON、CSVなど)で出力する際に、それぞれの形式に応じた適切なエスケープを行うことができます。

2. 【重要】なぜ「ブラックリスト方式」は推奨されないのか?
よくある誤った対策として、「<script> という文字列を削除する」というブラックリスト方式のフィルタリングがあります。しかし、セキュリティの世界では「ブラックリスト方式は抜け穴だらけ」と言われ、推奨されません。
なぜなら、攻撃者は <script> タグを使わずにJavaScriptを実行する方法を無数に知っているからです。
ブラックリストをすり抜ける攻撃例:
<img src=x onerror=alert(1)>: 画像の読み込みに失敗したタイミングでスクリプトを実行させます。<script>という文字は一切使われていません<body onload=alert(1)>: ページの読み込み完了時に実行させます<a href="javascript:alert(1)">: リンクをクリックした時に実行させます- 大文字小文字を変える(
<ScRiPt>): 大文字小文字を区別しないフィルタを回避 - スペースの代わりにスラッシュを入れる(
<script/src=...>): HTMLパーサーの寛容な仕様を悪用 - エンコーディングを利用する(
%3Cscript%3E): URLエンコードやHTMLエンティティを使った回避 - NULL文字を挿入する(
<scri\0pt>): 一部の処理系ではNULL文字が無視される - コメントアウトを利用する(
<scr<!--comment-->ipt>): HTMLコメントを挟んでフィルタを回避
このように、攻撃パターンを全て予測してリストアップすることは不可能です。攻撃者は常に新しい回避手法を考案しており、ブラックリスト方式では追いつけません。
実際の開発現場でも、ブラックリスト方式を採用したことで後から脆弱性が発見され、緊急対応に追われるケースが後を絶ちません。あるECサイトでは、<script> タグを削除する処理を実装していましたが、<img> タグの onerror 属性を使った攻撃により、数百件のクレジットカード情報が漏洩する事故が発生しました。
だからこそ、特定の悪いものを排除するのではなく、安全な形(エスケープ済みの文字列)に変換して出力する、あるいは「許可された文字種以外は受け入れない(ホワイトリスト方式)というアプローチが必須となるのです。
ホワイトリスト方式の例としては、郵便番号の入力欄であれば「数字とハイフンのみ許可」、メールアドレスであれば「RFC準拠のメールアドレス形式のみ許可」といった具合に、許可するものを明示的に定義します。これにより、想定外の入力をすべて排除できます。
3. 【根本的対策】URLのスキーム制限
<a> タグのリンク先などをユーザー入力から生成する場合、javascript: スキームによる攻撃を防ぐ必要があります。リンク先は http:// または https:// から始まるものだけに限定(ホワイトリスト化)し、それ以外は排除します。
javascript: スキームを使うと、リンクをクリックした際にJavaScriptコードが実行されます。たとえば <a href="javascript:alert('XSS')">クリック</a> というリンクは、クリックするとアラートが表示されます。これを悪用すれば、Cookieの窃取や画面改ざんが可能になります。
他にも data: スキームや vbscript: スキームなど、危険なスキームは複数存在します。そのため、ホワイトリスト方式で安全なスキームのみを許可することが重要です。
実装例としては、URLをバリデーションする関数を用意し、必ず http:// または https:// で始まることを確認してからリンクとして出力します。また、相対URLを使用する場合は、サーバー側で絶対URLに変換してからバリデーションを行うと安全性が高まります。
4. 【根本的対策】DOM Based XSSへの対応
JavaScriptでDOMを操作する際は、適切なプロパティを使用します。
- NG:
innerHTML,document.write(HTMLとして解釈される) - OK:
textContent,innerText(単なるテキストとして扱われる)
innerHTML を使うと、代入された文字列がHTMLとして解釈されるため、その中にスクリプトタグが含まれていれば実行されてしまいます。一方、textContent や innerText を使えば、どんな文字列を代入してもテキストとしてのみ扱われるため、スクリプトが実行されることはありません。
どうしても動的にHTMLを生成する必要がある場合は、DOMPurifyなどのサニタイズライブラリを使用して、安全なHTMLのみを許可するようにしましょう。また、フレームワークが提供するテンプレート機能を使えば、自動的にエスケープが行われるため、より安全です。
5. 【緩和策】多層防御(HttpOnly, WAF, CSP)
万が一、実装漏れがあっても被害を最小限にするための「保険」です。
- HttpOnly属性: Cookieに付与することで、JavaScriptからのセッションID窃取を防ぎます
- WAF (Web Application Firewall): 攻撃パターンを含む通信を遮断します
- CSP (Content Security Policy): 許可したドメイン以外のスクリプト実行をブラウザ側でブロックさせます
HttpOnly属性は、Cookieに設定することでJavaScriptからそのCookieにアクセスできなくします。XSSが成功しても document.cookie でセッションIDを盗むことができなくなるため、セッションハイジャックのリスクを大幅に低減できます。サーバー側でCookieを設定する際は、必ずHttpOnly属性を付与するようにしましょう。
WAFは、Webアプリケーションの前段に配置し、SQLインジェクションやXSSなどの攻撃パターンを検知してブロックするセキュリティ製品です。既知の攻撃パターンに対しては有効ですが、ゼロデイ攻撃や高度に偽装された攻撃には対応できない場合があります。あくまで補完的な対策と位置づけましょう。
CSP(Content Security Policy)は、HTTPレスポンスヘッダーでスクリプトの実行ポリシーを宣言する仕組みです。たとえば Content-Security-Policy: script-src 'self' と設定すると、同じドメイン内のスクリプトしか実行できなくなります。これにより、攻撃者が外部サイトから悪意のあるスクリプトを読み込ませようとしても、ブラウザがブロックしてくれます。

多層防御の考え方は、「完璧な防御は存在しない」という前提に立っています。どれか一つの対策が破られても、他の層で被害を食い止められるように設計することで、システム全体の安全性を高めます。この考え方は、XSSだけでなく、あらゆるセキュリティ対策に通じる基本原則です。
【試験対策】近年の出題トレンドとCVSS評価
ここでは、情報処理安全確保支援士試験で高得点を狙うための「一歩進んだ知識」を解説します。
1. 開発プロセスにおける脆弱性管理
近年の試験(特に午後問題)では、単純なXSSの有無だけでなく、開発プロセスの中でどう防ぐかという視点で出題されることが増えています。
ソースコードレビュー: PHPやJavaのコード片が提示され、「この行の出力処理に問題がある。具体的にどう直すべきか?」と記述させる問題が頻出です。エスケープ関数名(PHPなら htmlspecialchars()、Javaなら StringEscapeUtils.escapeHtml4() など)を正確に答えられるようにしておきましょう。
また、コードレビューでは「なぜこのコードが危険なのか」を説明する記述問題も出題されます。たとえば「ユーザー入力をそのままHTMLに埋め込んでいるため、スクリプトタグが含まれていた場合にブラウザで実行される」といった論理的な説明ができるかが試されます。
脆弱性スキャンツール(DAST/SAST)の活用: ツールが検出した「XSSの疑い」に対し、それが本当に修正すべき脆弱性なのか、誤検知(False Positive)なのかを判断させる問題も増えています。ツールの出力結果を読み解き、どこに問題があるのかを特定する能力が求められます。
DASTは動的解析ツールで、実際にアプリケーションを動かしながら攻撃を試みて脆弱性を検出します。一方、SASTは静的解析ツールで、ソースコードを解析して脆弱性の可能性がある箇所を指摘します。それぞれの特性を理解し、どちらが適切かを判断できるようにしましょう。
セキュアコーディング規約の策定: 「フレームワークの標準機能(自動エスケープ)を使用する」「innerHTML などの危険な関数は原則禁止する」といったルールを組織として定める能力が問われます。試験では、具体的な規約項目を列挙させる問題や、規約違反のコードを指摘させる問題が出題されます。
たとえば、Webアプリケーションフレームワークの多くは、テンプレートエンジンで自動的にエスケープを行う機能を持っています。開発者がこの機能を無効化したり、素のJavaScriptで直接DOMを操作したりすると、脆弱性が生まれやすくなります。規約でこうした危険な書き方を禁止し、コードレビューで徹底することが重要です。
モダンフレームワークの落とし穴: ReactやVue.jsなどはデフォルトでエスケープを行いますが、開発者が意図的にその機能を無効化した場合(例:Reactの dangerouslySetInnerHTML)にリスクが生じる点も押さえておきましょう。試験では「このフレームワークを使っていれば安全か?」という問いに対して、「基本的には安全だが、開発者が不適切に機能を無効化すると脆弱性が生まれる」といった答え方が求められます。
フレームワークの安全機能を理解することは重要ですが、それに依存しすぎるのも危険です。フレームワークのバージョンアップで挙動が変わったり、ライブラリの組み合わせで予期しない動作をしたりすることもあります。基本的なセキュリティ原則を理解した上でフレームワークを使いこなすことが大切です。
2. CVSS v3 で見るXSSの深刻度
脆弱性の深刻度評価(CVSS)において、XSSはどのようにスコアリングされるかを知っておくと、問題文の状況把握がスムーズになります。
- 攻撃元区分 (AV): ネットワーク (Network) - Web経由で攻撃可能です
- ユーザ関与レベル (UI): 要 (Required) - ここが重要です。 XSSは被害者がURLをクリックしたり、ページを閲覧したりする必要があります。サーバーを直接攻撃するSQLインジェクションとの大きな違いです
- 機密性への影響 (C): 低〜高 - Cookie窃取によるセッションハイジャックが可能なら「高」になります
- 完全性への影響 (I): 低〜高 - 画面の改ざんが可能なためです
総合スコアとしては Medium〜High 程度になることが多いですが、セッションハイジャックにより管理者権限を奪取できる場合は、その後の二次被害を含めると極めて危険度が高くなります。試験では「UI: 要」という特性がヒントになることも多いので覚えておきましょう。
CVSS評価を理解しておくと、問題文で「この脆弱性の深刻度はどの程度か」と問われた際に、適切な根拠とともに答えることができます。たとえば「ユーザーの操作が必要なため攻撃の難易度は中程度だが、管理者アカウントを乗っ取れる可能性があるため、影響度は高い」といった分析ができます。
また、CVSS v3では「攻撃条件の複雑さ (AC)」という指標もあります。XSSの場合、基本的には「低 (Low)」と評価されることが多いです。特別な条件や設定を必要とせず、単純にURLをクリックさせるだけで攻撃が成功するためです。
さらに、「影響の範囲 (S)」という指標では、XSSが他のユーザーやシステムに波及するかを評価します。蓄積型XSSの場合、一度の攻撃で不特定多数に影響が及ぶため、スコアが高くなる傾向があります。
【演習】XSS(クロスサイトスクリプティング)理解度チェック
記事で学んだ「クロスサイトスクリプティング(XSS)」の重要ポイントを、クイズ形式で復習しましょう。 「反射型・蓄積型・DOM Based」の判別や、適切なサニタイジング手法など、試験によく出る要素を詰め込みました。全10問、解説付きです。
まとめ:攻撃の検出からコード修正までをイメージしよう
今回の記事では、XSSの基礎から、ブラックリスト方式の限界、そして試験での実践的なトレンドまでを解説しました。
XSSは「知っていれば防げる」脆弱性です。しかし、正しい知識なく場当たり的な対策を行うと、抜け穴だらけになってしまいます。特にブラックリスト方式は一見有効に見えますが、攻撃者は常に新しい回避手法を編み出すため、いたちごっこになります。
根本的な対策は、出力時のエスケープ処理です。これを徹底することで、どんな攻撃手法にも対応できます。加えて、HttpOnly属性やCSPなどの多層防御を組み合わせることで、万が一の実装漏れにも備えられます。
情報処理安全確保支援士試験では、単なる知識の暗記ではなく、実際のシステム開発における判断力が問われます。コードレビューで脆弱性を発見し、適切な修正方法を提案できる能力、脆弱性スキャンツールの結果を正しく解釈できる能力、そして組織全体でセキュリティを高めるための仕組みを設計できる能力が求められます。
過去問演習を通して、「攻撃の検出」から「コード修正」、そして「再発防止策の策定」までの一連の流れをスムーズに行えるようトレーニングを積んでください。XSSの問題は、午後試験で毎年のように出題される最重要テーマです。この記事で学んだ知識を基礎として、実践的な問題演習を重ねることで、確実に合格ラインを突破できるでしょう。
最後に、XSSは試験対策だけでなく、実務でも極めて重要なテーマです。資格取得後も、最新の攻撃手法やフレームワークの動向を追い続け、常にスキルをアップデートしていく姿勢が、優れたセキュリティエンジニアには求められます。この記事が、その第一歩となれば幸いです。
文字数: 8,847文字(HTMLタグ、画像プロンプトを除く)