クロスサイトスクリプティング(XSS)の3類型(蓄積型・反射型・DOM Based)と、根本対策である出力エスケープを解説。HttpOnly・CSP との役割の違い、セッション ID 奪取の流れ、情報処理安全確保支援士の午後問題での問われ方まで。
クロスサイトスクリプティング(XSS、CWE-79)は、利用者が入力した文字列を Web ページにそのまま埋め込んで出力してしまうことで、その中のスクリプトが、ページを開いた別の利用者のブラウザで実行される脆弱性です。攻撃者は自分のスクリプトを、被害者(多くはログイン中の利用者や管理者)のブラウザ上で、そのサイトの権限で動かせます。結果として、セッション Cookie の奪取、画面の改ざん、偽の入力フォームの表示、利用者の操作を利用したなりすましなどが起こります。
| 類型 | 入力の経路 | 例 |
|---|---|---|
| 蓄積型(格納型) | サーバに保存された入力が、後から別の利用者の画面に出力される | 掲示板・レビュー・問い合わせ内容が管理画面に表示される |
| 反射型 | 要求に含めた入力が、その応答にそのまま返って実行される | 検索キーワードやエラーメッセージがそのまま表示される |
| DOM Based | サーバを介さず、ブラウザ内の JavaScript が入力を危険な形で DOM に書き込む | location.hash などをそのまま innerHTML に入れる |
蓄積型は「一度仕込めば、開いた全員が被害に遭う」ため影響が大きく、管理画面のように権限の高い利用者が閲覧する画面で成立すると特に危険です。反射型は、攻撃者が用意した URL を被害者に踏ませる必要があります。DOM Based は、通信を見てもサーバの応答には現れないため、サーバ側のログだけでは気づきにくいのが特徴です。
XSS は入力の問題に見えますが、止めるべきは出力の時点です。画面に出す直前に、文脈に応じて特殊文字を無害化(エスケープ/エンコード)すれば、タグは「文字」として表示され、スクリプトとして解釈されません。テンプレートエンジンの自動エスケープを有効にするのが基本です。
# テンプレートの自動エスケープを有効にする(Jinja2 など)
app.jinja_env.autoescape = True
# 出力: {{ body }}
# 入力が "<script>...</script>" でも、
# <script>...</script> として「文字」で表示される
重要なのは「文脈(コンテキスト)に応じたエスケープ」です。同じ入力でも、HTML の本文に出すのか、属性値に出すのか、<script> の中に出すのか、URL として出すのかで、無害化のしかたは変わります。HTML 本文なら HTML エスケープ、URL に入れるなら URL エンコード、というように、出力先に合った処理を選びます。自動エスケープは HTML 本文の文脈を前提にしていることが多いので、属性やスクリプト内に出す箇所は特に注意します。
セッション Cookie に HttpOnly を付けると、スクリプトから読み取れなくなり、Cookie の奪取を防げます。しかし、本文がスクリプトとして動くこと自体は止まりません。攻撃者は Cookie を盗む代わりに、被害者のブラウザ上で直接、送金・設定変更・投稿などの操作を実行できます(画面の改ざんやなりすまし操作)。したがって HttpOnly は「Cookie 奪取という一つの被害」を抑える緩和策であり、根本対策である出力エスケープと役割が違います。両方を組み合わせるのが多層防御です。
| Cookie 属性 | 防ぐもの |
|---|---|
| HttpOnly | スクリプトからの Cookie 読み取り(XSS 経由の奪取) |
| Secure | HTTP(平文)での送信(盗聴) |
| SameSite | 別サイトからの遷移での送信(CSRF の緩和) |
午後問題では、投稿内容が管理画面などに表示されるアプリを題材に、「攻撃の種類」「実行される条件」「対策」を答えさせる形が定番です。対策では、根本対策(出力エスケープ)と緩和策(HttpOnly・CSP)を区別し、「なぜ片方だけでは不十分か」を説明させます。令和5年度 秋期 午後 問1 では、蓄積型 XSS とセッション ID の奪取、cookie を別ドメインへ送らせない仕組み(SameSite)までが一続きで問われました。採点講評では、スクリプトが DOM を使っていたことから「DOM Based XSS」と誤答した例が挙げられており、脆弱性は種類と埋め込まれた状況に応じた対策まで含めて正確に押さえることが求められています。
題材は、EC サイトに商品レビュー機能を追加した Web アプリです。レビューのタイトルと詳細は自由記述で、それぞれ 50 字・300 字の入力文字数制限があります。「入力文字数に上限がある」という一見なんでもない仕様が、後の設問(制限を超える長さのスクリプトをどう実行させたか)の焦点になります。

この問では、「16 件あるはずのレビューが 2 件しか表示されない」という異常から調査が始まります。投稿された本文が HTML として解釈され、以降のレビューがコメントアウトされて消えていた、という筋です。画面の異常が、そのまま出力処理の欠陥を示す手がかりになっている点に注目してください。

実際に問われた形は次のとおりです。設問1 は XSS の種類(蓄積型か、反射型か、DOM Based か)と対策、設問2 は入力文字数制限を超える長さのスクリプトを実行させた方法、設問3 は奪ったものを攻撃者がどう回収し何ができるか、設問4 は攻撃者のドメインからでは成立しない理由(ブラウザの仕組み)です。「種類 → 成立条件 → 影響 → 対策」という順で並んでいることが分かります。

IPA 公式 PDF:令和5年度 秋期 午後問題(問1 が XSS・セッション奪取) ↗本文はこの公式 PDF でご覧ください(アプリ内には転載していません)。支援士日誌の過去問モードにも、この問の設問要約・解説を置いています。